【问题标题】:How to set a Bindíng in C#如何在 C# 中设置绑定
【发布时间】:2016-12-01 14:15:09
【问题描述】:

我读过一些书 (galli) 并在网站上进行了一些研究。问题是我觉得我没听懂。

我试图做的是创建一个自定义形状(六边形)的按钮。当用户点击它时,它应该改变颜色。

在找到thisthat 之后,我创建了以下内容:

 public class hexButton : System.Windows.Controls.Button
{
    public SolidColorBrush borderColor { get; set; }
    public SolidColorBrush fillColor {get;set;}
    public int Height { get; private set; }
    public int Width { get; private set; }
    public Point Location { get; private set; }
    private Hexagon hex;

    public hexButton() : this(50,0,0,Colors.Yellow, Colors.Brown){}    

    public hexButton(int sideLenght, int positionX, int positionY, Color border, Color fill):base()
    {
        borderColor = new SolidColorBrush(border);
        fillColor = new SolidColorBrush(fill);
        hex = new Hexagon(sideLenght, positionX, positionY);

        Binding binding = new Binding();
        binding.Path = new PropertyPath("FillProperty");
        binding.Source = fillColor;
        BindingOperations.SetBinding(hex.polygon, Polygon.FillProperty, binding);

        ControlTemplate t = new ControlTemplate(typeof(Button));
        FrameworkElementFactory fef = new FrameworkElementFactory(typeof(Polygon));
        fef.Name = "Polygon";
        fef.SetValue(Polygon.PointsProperty, hex.polygon.Points);
        fef.SetBinding(Polygon.FillProperty, binding); //doesent work
        fef.SetValue(Polygon.StrokeThicknessProperty, hex.polygon.StrokeThickness);
        //fef.SetValue(Polygon.FillProperty, fillColor); // works at least for the constructor
        fef.SetValue(Polygon.StrokeProperty, borderColor);
        t.VisualTree = fef;

        Style hexButtonStyle = new Style(typeof(Button));
        hexButtonStyle.Setters.Add(new Setter(Button.TemplateProperty, t));

        this.Style = hexButtonStyle;
        this.Height = hex.Y_Max - hex.Y_Min;
        this.Width = hex.X_Max - hex.X_Min;
        this.Location = hex.location;
    }

我也有一个六边形类:

    public class Hexagon
{
    private int _Height;
    private int _Diameter;
    private int _SideLenght;
    public Polygon polygon { get; set; }
    public int Y_Min { get; private set; }
    public int Y_Max { get; private set; }
    public int X_Min { get; private set; }
    public int X_Max { get; private set; }
    public Point location { get; set; }

    public Hexagon() : this(30) { }

    public Hexagon(int sideLenght): this (sideLenght,0,0) { }

    public Hexagon(int sideLenght, Point location): this(sideLenght,(int)location.X, (int)location.Y){}

    public Hexagon(int sideLenght, int locationX, int locationY)
    {
        if (sideLenght <= 0)
        {
            sideLenght = 30;
        }
        _SideLenght = sideLenght;
        calcHeight();
        calcDiameter();
        location = new Point(locationX, locationY);
        polygon = new Polygon();
        polygon.Points.Clear();
        polygon.StrokeThickness = 4;
        createHexPolygon();
    }

    private void calcHeight()
    {
        //h = (√3)s
        _Height = Convert.ToInt32(Math.Pow(3,0.5)*_SideLenght);
    }

    private void calcDiameter()
    {
        _Diameter = 2 * _SideLenght;
    }

    private void createHexPolygon()
    {   //        0           1
        //         __________
        //        /          \
        //       /            \
        //      /              \  2
        //    5 \              /
        //       \            /
        //        \__________/
        //        4           3

        Point p = new Point();
        p.X = _SideLenght / 2;
        p.Y = 0;
        p.X = p.X + location.X + 2; // +2 =offset von StrokeThickness (siehe konstruktor)
        p.Y = p.Y + location.Y + 2;
        polygon.Points.Add(p);
        p.X = _SideLenght + (_SideLenght / 2);
        p.Y = 0;
        p.X = p.X + location.X + 2;
        p.Y = p.Y + location.Y + 2;
        polygon.Points.Add(p);
        p.X = _Diameter;
        p.Y = _Height / 2;
        p.X = p.X + location.X + 2;
        p.Y = p.Y + location.Y + 2;
        polygon.Points.Add(p);
        p.X = _SideLenght + (_SideLenght / 2);
        p.Y = _Height;
        p.X = p.X + location.X + 2;
        p.Y = p.Y + location.Y + 2;
        polygon.Points.Add(p);
        p.X = _SideLenght / 2;
        p.Y = _Height;
        p.X = p.X + location.X + 2;
        p.Y = p.Y + location.Y + 2;
        polygon.Points.Add(p);
        p.X = 0;
        p.Y = _Height / 2;
        p.X = p.X + location.X + 2;
        p.Y = p.Y + location.Y + 2;
        polygon.Points.Add(p);

        X_Min = (int)polygon.Points[5].X;
        X_Max = (int)polygon.Points[2].X + 2;
        Y_Min = (int)polygon.Points[0].Y;
        Y_Max = (int)polygon.Points[3].Y + 2;
    }

}

供以后使用(单击按钮时 - 需要属性更改事件)我想用它来重置绑定:

        private void SetBinding()
    {
        Binding binding = new Binding();
        binding.Path = new PropertyPath("FillProperty");
        binding.Source = fillColor;
        BindingOperations.SetBinding(hex.polygon, Polygon.FillProperty, binding);
    }

我认为问题出在此处:

Binding binding = new Binding();
        binding.Path = new PropertyPath("FillProperty");
        binding.Source = fillColor;
        BindingOperations.SetBinding(hex.polygon, Polygon.FillProperty, binding);

        //....

        fef.SetBinding(Polygon.FillProperty, binding);


1. Why is the binding not working?
2. What do I need to do to make it work?
3. I read somewhere (don't know where) that creating styles and bindings in code (behind) is not really recommended
    - What would be another way to do this?
    - Why is it not recommended?

【问题讨论】:

  • 我建议在 xaml 中执行此操作,因为 WPF 与 win 表单相比的一大重点是分离 UI 和逻辑代码
  • @Ash :你说得对,唯一的区别是我取消了 Polygon 而不是 PathCanvas Grid 但变化不大。它可以正常工作。但是,有没有办法绑定 PathPathPoints (以便我可以根据 按钮的宽度高度)?我没有看到适合的 DependencyProperty... 我可以自己创建吗?如果是,它是如何完成的?
  • 顺便说一句:如果发现this真的很有帮助

标签: c# wpf button binding


【解决方案1】:

在非常基础的层面上,绑定是通过使用 UI 元素的 DataContext 属性完成的。例如,如果你有一个 Person 类:

public class Person
{
     public string FirstName {get;set;}
     public string LastName {get;set;}
}

然后,您可以使用绑定将这些属性绑定到 UI 元素,而无需显式设置它们。例如,如果您有一个 StackPanel

<StackPanel x:Name="MyStack" Orientation="Horizontal">
    <TextBlock Text="{Binding FirstName}"/>
    <TextBlock Text="{Binding LastName}"/>
</StackPanel>

此 XAML 将在设置的 DataContext 中查找任何名为 FirstName 或 LastName 的属性。所以通过将DataContext设置为Person对象,就可以显示我们指定的数据了。

MyStack.DataContext = new Person(){ FirstName = "Test", LastName = "Man"};

这将告诉 StackPanel 用“Test”和“Man”填充这两个文本框。

此逻辑扩展到任何类型的 UI 对象,例如用于设置颜色的 SolidColorBrush。如果您扩展 Person 类以接受 FavColor 属性的 SolidColorBrush 属性,那么您也可以通过为其设置绑定来设置面板的背景,即

&lt;StackPanel x:Name="MyStack" Background="{Binding FavColor}" Orientation="Horizontal"&gt;

但是,如前所述,您确实希望将模型(包含您要显示的数据的对象,如我们的 Person、User 或 Shape 等)与任何类型的 View 信息完全分开。要详细了解如何执行此操作,我将研究模型视图视图模型 (MVVM) 模式,该模式主要关注 XAML 数据绑定。那里有很多很好的教程,我使用视频示例来帮助我理解,因此可能也值得搜索这些以扩展您的知识。

【讨论】:

    【解决方案2】:
    Binding binding = new Binding();
    binding.Path = new PropertyPath("FillProperty");
    binding.Source = fillColor;
    BindingOperations.SetBinding(hex.polygon, Polygon.FillProperty, binding);
    

    该代码创建一个绑定,其SourceSolidColorBrush,其PathFillProperty

    这意味着绑定将转到Source 对象,并在该Source 对象上查找名为FillProperty 的属性,然后它将该属性的值传递给Fill 多边形的属性。

    这不是你想要的:SolidColorBrush 没有名为 FillProperty 的属性(什么都没有),它也没有名为 Fill 的属性。 Fill 是目标属性,而不是源属性。你想要的是这样的:

    hex.polygon.Fill = fillColor;
    

    在这种特殊情况下使用绑定没有用,因为fillColor 是一个局部变量。您使用属性绑定,以便当源更改时,目标将被更新(和/或目标更改可能会更新源,具体取决于参数)。

    但是为了了解Binding 的工作原理,这也应该做你想做的:

    Binding binding = new Binding();
    binding.Source = fillColor;
    BindingOperations.SetBinding(hex.polygon, Polygon.FillProperty, binding);
    

    我看到一些关于 Polygon.FillPropertyPolygon.Fill 的混淆。 Polygon.FillPropertypublic static readonly DependencyProperty object which describes the characteristics of the Polygon's Fill dependency propertyPolygon 也有一个名为 Fill 的常规属性,你可以直接使用它,就像我上面展示的那样。公共静态只读 DependencyProperty 对象的名称与名义依赖属性相同,后缀为“Property”,这是一个约定,但这不是绝对必需的。

    【讨论】:

      猜你喜欢
      • 2011-06-07
      • 1970-01-01
      • 2016-01-15
      • 2011-11-23
      • 1970-01-01
      • 2021-12-26
      • 2013-02-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多