简体   繁体   English

使用C#绑定到WPF中的UserControl

[英]Binding to a UserControl in WPF using C#

Preface The control I am giving as an example is an sample work for a larger project. 前言我作为示例给出的控件是一个较大项目的示例工作。 I have already had some help from the community on Stackoverflow ironing out some of the finer points of bindings within the control. 我已经从Stackoverflow社区获得了一些帮助,以消除控件中绑定的一些细节。 The surprise has been that I am having an issue binding in the control's hosting form. 令人惊讶的是,我在控件的托管表单中遇到绑定问题。

I have read and researched around DependencyProperty for a lot of hours. 我已经阅读并研究了DependencyProperty了很多小时。 I was not a WPF developer at the start of the year but I am now covering the role because of a death in the business, and I accept this is a big hill to climb. 我在年初不是WPF开发人员,但是由于业务的失败,我现在要担任这个职位,并且我认为这是一个艰巨的任务。

The question is what is missing here in my: 问题是我的这里缺少什么:

The hosting form's XAML code 托管表单的XAML代码

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:AControl="clr-namespace:AControl;assembly=AControl" x:Class="DependencySampler.MainWindow"
    Title="MainWindow" Height="350" Width="525">
<Grid>

    <AControl:UserControl1 x:Name="cboBob" HorizontalAlignment="Left" Margin="100,118,0,0" VerticalAlignment="Top" Width="200" Height="29" SelectedColor="{Binding Path=BeSelected, Mode=OneWayToSource}"/>

</Grid>

The code behind 背后的代码

    public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new viewModelBinding();
        BeSelected =  new modelMain("Yellow", "#FFFFE0");
    }

    public modelMain BeSelected
    { 
        get { return ((viewModelBinding)DataContext).Selected; }
        set { ((viewModelBinding)DataContext).Selected = value; }
    }

}

The ViewModel ViewModel

    public class viewModelBinding :ViewModelBase
{
    modelMain sel = new modelMain("Red", "#FF0000");
    public modelMain Selected
    {
        get { return sel; }
        set { SetProperty(ref this.sel, value, "Selected"); }
    }
}

The next section is the control itself. 下一部分是控件本身。

The Model 该模型

    public class modelMain:ViewModelBase
{
    public modelMain(string colName, string hexval)
    {
        ColorName = colName;
        HexValue = hexval;
    }

    string colorName;
    public string ColorName
    {
        get { return colorName; }
        set { SetProperty(ref this.colorName, value, "ColorName"); }
    }

    string hexValue;
    public string HexValue
    {
        get { return hexValue; }
        set { SetProperty(ref this.hexValue, value, "HexValue"); }
    }
}

The ViewModel ViewModel

    public class viewModelMain:ViewModelBase
{
    ObservableCollection<modelMain> val = new ObservableCollection<modelMain>();
    public ObservableCollection<modelMain> ColorsList
    {
        get { return val; }
        set { SetProperty(ref this.val, value, "Colors"); }
    }


    modelMain selectedColor;
    public modelMain SelectedColour
    {          
        get{return selectedColor;}
        set { SetProperty(ref this.selectedColor, value, "SelectedColour"); }
    }

    public void SetCurrentColor(modelMain col)
    {
        SelectedColour = this.val.Where(x => x.ColorName == col.ColorName).FirstOrDefault(); 
    }

    public viewModelMain()
    {
        val.Add(new modelMain("Red", "#FF0000"));
        val.Add(new modelMain("Blue", "#0000FF"));
        val.Add(new modelMain("Green", "#008000"));
        val.Add(new modelMain("Yellow", "#FFFFE0"));

        SelectedColour = new modelMain("Blue", "#0000FF");
    }
}

The UserControl XAML UserControl XAML

<UserControl x:Class="AControl.UserControl1"
         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" 
         mc:Ignorable="d" 
         d:DesignHeight="32" d:DesignWidth="190">
<Grid>
    <ComboBox x:Name="cboValue"
              SelectionChanged="cboValue_SelectionChanged"
              HorizontalAlignment="Stretch"
              VerticalAlignment="Stretch"
              ItemsSource="{Binding ColorList, RelativeSource={RelativeSource AncestorType=UserControl}}"
              SelectedValue="{Binding SelectedColor, RelativeSource={RelativeSource AncestorType=UserControl}}">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Width="10"
                               Height="10"
                               Margin="5"
                               Background="{Binding ColorName}"/>
                    <TextBlock Width="35"
                               Height="15"
                               Margin="5"
                               Text="{Binding ColorName}"/>
                </StackPanel>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox> 
</Grid>

The UserControl Code behind 后面的UserControl代码

    public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
    }

    ObservableCollection<modelMain> colorList = new viewModelMain().ColorsList;
    public ObservableCollection<modelMain> ColorList
    {
        get { return colorList; }
        set { colorList = value; }
    }


    public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register(
        "SelectedColor",
        typeof(modelMain),
        typeof(UserControl1),
        new FrameworkPropertyMetadata(
            null, 
            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
            new PropertyChangedCallback(OnSelectedColorChanged),
            new CoerceValueCallback(CoerceSelectedColorCallback)));


    private static void OnSelectedColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        UserControl1 uc = (UserControl1)d;
        uc.SelectedColor = (modelMain)e.NewValue;
    }

    private static object CoerceSelectedColorCallback(DependencyObject d, object value)
    {
        return (modelMain)value;
    }


    public modelMain SelectedColor
    {
        get { return (modelMain)GetValue(SelectedColorProperty); }
        set { SetValue(SelectedColorProperty, value); }
    }

    private void cboValue_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var dat = sender as ComboBox;
        SelectedColor = (modelMain)dat.SelectedValue;
    }

    private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
        //var dat = sender as ComboBox;
        ////SelectedColor = (modelMain)dat.SelectedValue;
        //SelectedColor = (modelMain)this.SelectedColor;
    }
}

Please note that in the code behind there is unused code but within the sample I have used then for placing break points 请注意,在后面的代码中有未使用的代码,但是在我用来放置断点的示例中

I understand that no DataContext should exist in the UserControl because it precludes one in the hosting form. 我知道UserControl中不应该存在DataContext,因为它排除了宿主形式中的一个。

The Question I was expecting the this line would be sufficient in the hosting form. 我期望的问题是托管表格中的这一行就足够了。

<AControl:UserControl1 x:Name="cboBob" HorizontalAlignment="Left" Margin="100,118,0,0" VerticalAlignment="Top" Width="200" Height="29" SelectedColor="{Binding Path=BeSelected, Mode=OneWayToSource}"/>

But it does not seem to do what I expected. 但这似乎并没有达到我的预期。 I can see the BeSelected be initialised and it is holding a value but when the form loads I am expecting the colour yellow to enter the UserControl's and set DependencyProperty SelectedColor. 我可以看到BeSelected已初始化,并且它拥有一个值,但是在加载表单时,我期望黄色进入UserControl并设置DependencyProperty SelectedColor。 This is not happening why and how can I get it to happen? 这没有发生,为什么以及如何使它发生?

To get you example working, do the following (for the most part, implement what the commenters said): 为了使您的示例正常工作,请执行以下操作(大部分情况下,请执行评论者所说的内容):

The hosting form's XAML code 托管表单的XAML代码

<AControl:UserControl1 x:Name="cboBob" HorizontalAlignment="Left" Margin="100,118,0,0" VerticalAlignment="Top" Width="200" Height="29" SelectedColor="{Binding Path=BeSelected, RelativeSource={RelativeSource AncestorType=Window}}}"/>

The Mode doesn't really matter since MainWindow doesn't implement INPC nor does it ever know when ((viewModelBinding)DataContext).Selected (and therefor, BeSelected) is changed. 模式并不重要,因为MainWindow不实现INPC,也不知道何时((viewModelBinding)DataContext).Selected(因此,BeSelected)被更改。 Actually, like Joe stated, OneWayToSource doesn't work... RelativeSource was needed because BeSelected is a property of the MainWindow - not MainWindow's DataContext. 实际上,就像乔所说的那样,OneWayToSource不起作用... RelativeSource是必需的,因为BeSelected是MainWindow的属性,而不是MainWindow的DataContext。

modelMain modelMain

modelMain needs to implement IEquatable (like Janne commented). modelMain需要实现IEquatable(如Janne所说)。 Why? 为什么? Because BeSelected = new modelMain(...) creates a new modelMain which is not one of the items in the ComboBox's ItemsSource (ColorList). 因为BeSelected = new modelMain(...)创建了一个新的modelMain,所以它不是ComboBox的ItemsSource(ColorList)中的项目之一。 The new object may have the same property values as one of the items but that doesn't make them equal (different objects = different address in memory). 新对象可能具有与其中一项相同的属性值,但是并不能使它们相等(不同的对象=内存中的不同地址)。 IEquatable gives you the opportunity to override that. IEquatable给您机会来覆盖它。

public class modelMain : ViewModelBase, IEquatable<modelMain>
{
  ...
  public bool Equals(modelMain other)
  {
    return (HexValue == other.HexValue);
  }
}

viewModelMain's ColorList's setter is calling SetProperty with property name "Colors" when it should be "ColorsList". viewModelMain的ColorList的设置方法应将属性名称为“ Colors”的SetProperty设置为“ ColorsList”。 It's not being used so it doesn't stop your example from working but it's still wrong. 它没有被使用,因此不会阻止您的示例工作,但这仍然是错误的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM