繁体   English   中英

使用C#绑定到WPF中的UserControl

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

前言我作为示例给出的控件是一个较大项目的示例工作。 我已经从Stackoverflow社区获得了一些帮助,以消除控件中绑定的一些细节。 令人惊讶的是,我在控件的托管表单中遇到绑定问题。

我已经阅读并研究了DependencyProperty了很多小时。 我在年初不是WPF开发人员,但是由于业务的失败,我现在要担任这个职位,并且我认为这是一个艰巨的任务。

问题是我的这里缺少什么:

托管表单的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>

背后的代码

    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; }
    }

}

ViewModel

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

下一部分是控件本身。

该模型

    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"); }
    }
}

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");
    }
}

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>

后面的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;
    }
}

请注意,在后面的代码中有未使用的代码,但是在我用来放置断点的示例中

我知道UserControl中不应该存在DataContext,因为它排除了宿主形式中的一个。

我期望的问题是托管表格中的这一行就足够了。

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

但这似乎并没有达到我的预期。 我可以看到BeSelected已初始化,并且它拥有一个值,但是在加载表单时,我期望黄色进入UserControl并设置DependencyProperty SelectedColor。 这没有发生,为什么以及如何使它发生?

为了使您的示例正常工作,请执行以下操作(大部分情况下,请执行评论者所说的内容):

托管表单的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}}}"/>

模式并不重要,因为MainWindow不实现INPC,也不知道何时((viewModelBinding)DataContext).Selected(因此,BeSelected)被更改。 实际上,就像乔所说的那样,OneWayToSource不起作用... RelativeSource是必需的,因为BeSelected是MainWindow的属性,而不是MainWindow的DataContext。

modelMain

modelMain需要实现IEquatable(如Janne所说)。 为什么? 因为BeSelected = new modelMain(...)创建了一个新的modelMain,所以它不是ComboBox的ItemsSource(ColorList)中的项目之一。 新对象可能具有与其中一项相同的属性值,但是并不能使它们相等(不同的对象=内存中的不同地址)。 IEquatable给您机会来覆盖它。

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

viewModelMain的ColorList的设置方法应将属性名称为“ Colors”的SetProperty设置为“ ColorsList”。 它没有被使用,因此不会阻止您的示例工作,但这仍然是错误的。

暂无
暂无

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

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