Я изо всех сил пытаюсь создать привязку из View + ViewModel к Custom ComboboxItem.Я не уверен, что это должно работать, я уже реализовал сложные UserControls и должен был правильно настроить DataContext, чтобы он работал с MVVM, но этот конкретный сценарий вообще не работает.
Что я пытаюсь сделать:
Создание пользовательского элемента управления на основе Combobox.Это будет иметь поведение Combobox, но оно настроено.Свернутый список со списком покажет только кнопку без Путь, а при раскрытии (показывает выпадающий список элементов со списком) он покажет больше настроенных кнопок.Этот UserControl должен работать с MVVM (который сейчас не работает).Если я устанавливаю содержимое ComboboxItem в жестко запрограммированном представлении View, оно отображается правильно, но если я пытаюсь выполнить привязку с viewmodel, происходит сбой:
System.Windows.Data Ошибка: 40: Ошибка пути BindingExpression: Свойство 'MessageName' не найдено в 'object' '' MultiButtonControl '(Name =' ')'.BindingExpression: Path = MessageName;DataItem = 'MultiButtonControl' (Name = '');целевой элемент - «TestComboBoxItem» (Name = '');целевым свойством является 'Content' (тип 'Object')
Я создал:
Пользовательский контроль MultiButtonControl, содержащий сетку и комбинированный список с определенным стилем иСписок с именем Children в коде позади (свойство зависимости).Я создаю привязку из выпадающего списка на xaml со свойством Children.
Пользовательский элемент управления TestComboBoxItem.cs, который расширяется из ComboBoxItem.И я создал в Generic.xaml стиль для этого типа.
DataContext:
Я установил DataContext из UserControl "MultiButtonControl.xaml"на родительском элементе -> элемент сетки как:
<Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
В настоящее время работает:
Прямо сейчас макет работает нормально.Я могу использовать свой UserControl в представлении, добавить детей.Но проблема в связывании.Я считаю, что проблема в DataContext.Потому что, когда я пытаюсь связать свойство из ComboboxItem (пользовательский элемент управления TestComboBoxItem), оно выходит из строя, и если я установил его жестко, оно работает.
Позвольте мне дать вам код:
View.xaml
<Window x:Class="Test2Manager.message.ModalMessageInsert"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Test2Manager.message"
xmlns:controls="clr-namespace:CSIncludes.controls;assembly=CSIncludes"
xmlns:wpf="clr-namespace:CSIncludes.wpf;assembly=CSIncludes"
mc:Ignorable="d"
WindowStyle="None"
AllowsTransparency="True"
WindowStartupLocation="CenterOwner"
WindowState="Maximized"
Background="#33000000"
Title="ModelMessageInsert"
Name="ModalWindow">
<Window.Resources>
<ResourceDictionary Source="/CSIncludes;component/Themes/Generic.xaml"/>
</Window.Resources>
<Grid Width="600" Height="400" VerticalAlignment="Center" HorizontalAlignment="Center" Background="Gray">
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"></TextBlock>
<Grid Grid.Row="1" Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="10"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center">Name:</TextBlock>
<TextBox Grid.Row="0" Grid.Column="2" VerticalAlignment="Center" Text="{Binding MessageName, UpdateSourceTrigger=PropertyChanged}">
<TextBox.Effect>
<DropShadowEffect Color="Yellow" Direction="270" ShadowDepth="2" Opacity="1" BlurRadius="2"></DropShadowEffect>
</TextBox.Effect>
</TextBox>
<!--<controls:AudioControl Grid.Row="2" Grid.Column="2" RecordingMode="False" ReproduceAudioPath="C:\Fabio\Musicas\05 - On The Turning Away.mp3"></controls:AudioControl>-->
<controls:MultiButtonControl Grid.Row="2" Grid.Column="2" Width="170" ParentButtonText="{Binding MessageName}" ParentButtonImage="/CSIncludes;component/images/audio_play.png">
<controls:MultiButtonControl.Children>
<!--Command2="{Binding TestCommand}"-->
<wpf:TestComboBoxItem Content="{Binding MessageName}"></wpf:TestComboBoxItem>
<wpf:TestComboBoxItem Content="Fabio 2"></wpf:TestComboBoxItem>
<wpf:TestComboBoxItem>Fabio 3</wpf:TestComboBoxItem>
</controls:MultiButtonControl.Children>
</controls:MultiButtonControl>
<!--<ComboBox Style="{StaticResource CustomCombobox}">
<ComboBoxItem>Item1</ComboBoxItem>
<ComboBoxItem>Item2</ComboBoxItem>
<ComboBoxItem>Item3</ComboBoxItem>
<ComboBoxItem>Item4</ComboBoxItem>
<ComboBoxItem>Item5</ComboBoxItem>
</ComboBox>-->
</Grid>
<StackPanel Orientation="Horizontal" Grid.Row="2" HorizontalAlignment="Center" Margin="5">
<Button Width="65" Command="{Binding SaveCommand}" CommandParameter="{Binding ElementName=ModalWindow}">Save</Button>
<Button Width="65" Command="{Binding CancelCommand}" CommandParameter="{Binding ElementName=ModalWindow}" Margin="5,0,0,0">Cancel</Button>
</StackPanel>
</Grid>
View - настройка кода для DataContext для ViewModel
using Arbeit.wpf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace Test2Manager.message
{
/// <summary>
/// Interaction logic for ModelMessageInsert.xaml
/// </summary>
public partial class ModalMessageInsert : Window
{
ViewModelModalMessageInsert vm;
public ModalMessageInsert(Test2Entities Context, Action UpdateList)
{
InitializeComponent();
vm = new ViewModelModalMessageInsert(Context, UpdateList);
DataContext = vm;
}
}
}
ViewModel
using CSIncludes.wpf;
using Test2EF;
using Test2Manager.database;
using Test2Manager.manager;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace Test2Manager.message
{
class ViewModelModalMessageInsert
{
private Test2Entities Context;
private MessageDAL MessageDAL;
private Action UpdateList;
private ModelMessage Model;
public ViewModelModalMessageInsert(Test2Entities Context, Action UpdateList)
{
this.Context = Context;
this.UpdateList = UpdateList;
MessageDAL = new MessageDAL(Context);
Model = new ModelMessage();
Model.ClientId = LoggedManager.ClientId;
MessageName = "Teste";
}
public string MessageName
{
get { return Model.Name; }
set
{
Model.Name = value;
}
}
}
}
MultiButtonControl.xaml
<UserControl x:Class="CSIncludes.controls.MultiButtonControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CSIncludes.controls"
xmlns:wpf="clr-namespace:CSIncludes.wpf"
mc:Ignorable="d"
d:DesignHeight="55" d:DesignWidth="300">
<UserControl.Resources>
<!--<ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border
x:Name="Border"
CornerRadius="0"
Background="#FF3F3F3F"
BorderBrush="#FF97A0A5"
BorderThickness="1" />
</Grid>
</ControlTemplate>-->
<ControlTemplate x:Key="ComboBoxTextBox" TargetType="{x:Type TextBox}">
<Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}" />
</ControlTemplate>
<Style x:Key="CustomCombobox" TargetType="{x:Type ComboBox}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="MinWidth" Value="120"/>
<Setter Property="MinHeight" Value="30"/>
<Setter Property="Foreground" Value="White"/>
<!--<Setter Property="DataContext" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"></Setter>-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid>
<!--Template="{StaticResource ComboBoxToggleButton}"-->
<ToggleButton
VerticalAlignment="Center"
Height="{Binding ParentButtonHeight}"
Name="ToggleButton"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Background" Value="#5F1E78"></Setter>
<Setter Property="BorderBrush" Value="#5F1E78"></Setter>
<Setter Property="BorderThickness" Value="1"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border BorderBrush="#FF97A0A5" BorderThickness="1" HorizontalAlignment="Center" Width="{TemplateBinding ActualWidth}">
<Grid Background="{TemplateBinding Background}" HorizontalAlignment="Center" Width="{TemplateBinding ActualWidth}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1" Margin="0,0,8,0" Foreground="White" Name="Text" Text="{Binding ParentButtonText}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Image Grid.Column="2" Name="Image" Width="16" Height="16" Source="{Binding ParentButtonImage}" />
</Grid>
<!--<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="16" />
</Grid.ColumnDefinitions>
<TextBlock Margin="10" Foreground="White" Grid.Column="0" Name="Text" Text="{Binding ParentButtonText}" HorizontalAlignment="Center" />
<Image Grid.Column="1" Name="Image" Source="{Binding ParentButtonImage}" />
</Grid>-->
</Border>
<!--<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="Text" Property="Foreground" Value="White" />
</Trigger>
</ControlTemplate.Triggers>-->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ToggleButton.Style>
</ToggleButton>
<!--<ToggleButton Content="aaa"
Name="ToggleButton"
Template="{StaticResource ComboBoxToggleButton}"
Grid.Column="2"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press">
</ToggleButton>-->
<TextBox x:Name="PART_EditableTextBox" Style="{x:Null}" Height="{Binding ParentButtonHeight}" Template="{StaticResource ComboBoxTextBox}" HorizontalAlignment="Left"
VerticalAlignment="Center" Focusable="True" Background="White" Foreground="Black" Visibility="Hidden" IsReadOnly="{TemplateBinding IsReadOnly}"/>
<Popup Name="Popup" Placement="Top" PlacementTarget="{Binding ElementName=PART_EditableTextBox}" IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="True" Focusable="False" PopupAnimation="Slide">
<Grid Name="DropDown" SnapsToDevicePixels="True" MinWidth="{TemplateBinding ActualWidth}" Width="{TemplateBinding ActualWidth}" MaxHeight="{TemplateBinding MaxDropDownHeight}" Height="{TemplateBinding ActualHeight}">
<Border x:Name="DropDownBorder" Background="White" BorderThickness="1" BorderBrush="#888888"/>
<ScrollViewer Margin="0,0,0,0" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#888888"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="0"/>
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,0,0,0"/>
</Trigger>
<Trigger Property="IsEditable" Value="true">
<Setter Property="IsTabStop" Value="false"/>
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
<!--<Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>-->
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
<ComboBox Style="{StaticResource CustomCombobox}" Focusable="False" x:Name="ComboBox" ItemsSource="{Binding Children}">
</ComboBox>
</Grid>
MultiButtonControl.xaml.cs
using CSIncludes.wpf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace CSIncludes.controls
{
/// <summary>
/// Interaction logic for MultiButtonControl.xaml
/// </summary>
public partial class MultiButtonControl : UserControl
{
public MultiButtonControl()
{
InitializeComponent();
this.Loaded += UserControl_Loaded;
Children = new List<TestComboBoxItem>();
}
public static readonly DependencyProperty ParentButtonTextProperty = DependencyProperty.Register(
"ParentButtonText",
typeof(string),
typeof(MultiButtonControl));
public static readonly DependencyProperty ParentButtonImageProperty = DependencyProperty.Register(
"ParentButtonImage",
typeof(ImageSource),
typeof(AudioControl),
new UIPropertyMetadata(null));
public static readonly DependencyProperty ParentButtonHeightProperty = DependencyProperty.Register(
"ParentButtonHeight",
typeof(double),
typeof(MultiButtonControl));
public static readonly DependencyProperty ChildButtonHeightProperty = DependencyProperty.Register(
"ChildButtonHeight",
typeof(double),
typeof(MultiButtonControl));
public static readonly DependencyProperty ChildrenProperty = DependencyProperty.Register(
"Children",
typeof(List<TestComboBoxItem>),
typeof(MultiButtonControl));
public string ParentButtonText
{
get { return (string)GetValue(ParentButtonTextProperty); }
set { SetValue(ParentButtonTextProperty, value); }
}
public ImageSource ParentButtonImage
{
get { return (ImageSource)GetValue(ParentButtonImageProperty); }
set { SetValue(ParentButtonImageProperty, value); }
}
public double ParentButtonHeight
{
get { return (double)GetValue(ParentButtonHeightProperty); }
set { SetValue(ParentButtonHeightProperty, value); }
}
public double ChildButtonHeight
{
get { return (double)GetValue(ChildButtonHeightProperty); }
set { SetValue(ChildButtonHeightProperty, value); }
}
public List<TestComboBoxItem> Children
{
get { return (List<TestComboBoxItem>)GetValue(ChildrenProperty); }
set { SetValue(ChildrenProperty, value); }
}
void UserControl_Loaded(object sender, RoutedEventArgs e)
{
if (ParentButtonHeight == 0)
ParentButtonHeight = 35;
if (ChildButtonHeight == 0)
ChildButtonHeight = 25;
ComboBox.MaxDropDownHeight = ComboBox.Items.Count * ChildButtonHeight;
}
}
}
Generic.xaml
<Style x:Key="{x:Type wpf:TestComboBoxItem}" TargetType="{x:Type wpf:TestComboBoxItem}">
<Setter Property="ComboBoxItem.SnapsToDevicePixels" Value="true"/>
<Setter Property="ComboBoxItem.Foreground" Value="Black"/>
<Setter Property="ComboBoxItem.OverridesDefaultStyle" Value="true"/>
<Setter Property="ComboBoxItem.Height" Value="{Binding ChildButtonHeight}"/>
<Setter Property="ComboBoxItem.VerticalAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TestComboBoxItem}">
<Border Name="Border" Padding="5" SnapsToDevicePixels="true">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="true">
<Setter TargetName="Border" Property="Background" Value="#7E59F2"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#888888"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
TestComboBoxItem.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace CSIncludes.wpf
{
public class TestComboBoxItem : ComboBoxItem
{
static TestComboBoxItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TestComboBoxItem), new FrameworkPropertyMetadata(typeof(ComboBoxItem)));
}
public static DependencyProperty CommandParameter2Property =
DependencyProperty.Register("CommandParameter2", typeof(object), typeof(TestComboBoxItem));
public static DependencyProperty Command2Property =
DependencyProperty.Register("Command2", typeof(ICommand), typeof(TestComboBoxItem));
public static DependencyProperty ItemTextProperty =
DependencyProperty.Register("ItemText", typeof(string), typeof(TestComboBoxItem));
public ICommand Command2
{
get { return (ICommand)GetValue(Command2Property); }
set { SetValue(Command2Property, value); }
}
public object CommandParameter2
{
get { return GetValue(CommandParameter2Property); }
set { SetValue(CommandParameter2Property, value); }
}
public string ItemText
{
get { return (string)GetValue(ItemTextProperty); }
set { SetValue(ItemTextProperty, value); }
}
}
}
Есть ли у вас какие-либоключ к пониманию того, как исправить привязки TestComboBoxItem?Как бы вы сделали, чтобы это работало?После привязки Контента мне нужно будет также создать привязки с ICommand.