我正在努力创建从View + ViewModel到Custom ComboboxItem的绑定。我不确定它是否应该工作,我已经实现了复杂的UserControls并且必须正确处理DataContext以使其与MVVM一起工作,但是这个特定的场景根本不起作用。
我要做的是:
基于Combobox创建用户控件。它将具有Combobox行为,但它是自定义的。组合框折叠后只显示一个没有Path的按钮,当展开(显示组合框项目的下拉列表)时,它将显示更多自定义的按钮。 此UserControl必须与MVVM(现在无法正常工作)一起使用。如果我在View硬编码上设置ComboboxItem的内容,它们会正确显示,但如果我尝试使用viewmodel进行绑定,则会失败:
System.Windows.Data错误:40:BindingExpression路径错误:'object'上找不到'MessageName'属性'''MultiButtonControl'(Name ='')'。 BindingExpression:路径= MessageName; DataItem ='MultiButtonControl'(Name =''); target元素是'TestComboBoxItem'(Name =''); target属性是'Content'(类型'Object')
我创建了:
一个usercontrol MultiButtonControl包含一个网格和一个具有特定样式的组合框和一个名为Children的代码隐藏在后面(依赖属性)。我使用Children属性从xaml上的组合框创建绑定。
从ComboBoxItem扩展的自定义控件TestComboBoxItem.cs。我在Generic.xaml上创建了该类型的样式。
的DataContext:
我在父元素上设置UserControl“MultiButtonControl.xaml”的DataContext - >网格元素为:
<Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
目前有效:
现在布局工作正常。我可以在View中使用我的UserControl,也可以添加Children。但问题是绑定。我相信问题是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>
查看 - 代码隐藏设置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;
}
}
}
视图模型
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创建绑定。