He leído algunos libros ( a>) e hice algunas investigaciones aquí en el sitio. El problema es que creo que no lo entendí.

Lo que intenté hacer es crear un botón con una forma personalizada (hexágono). Cuando el usuario hace clic en él, debería cambiar el color.

Después de encontrar this y que, creé lo siguiente:

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

También tengo una clase hexagonal:

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

}

Para uso posterior (al hacer clic en el botón - evento de cambio de propiedad necesario) quería usar esto para restablecer el enlace:

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

Creo que el problema está en algún lugar de aquí:

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?
0
Thoms 27 jul. 2016 a las 17:00

2 respuestas

La mejor respuesta

En un nivel muy básico, la vinculación se realiza mediante la propiedad DataContext de un elemento de la interfaz de usuario. Por ejemplo, si tuvieras una clase Person:

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

Luego, puede usar el enlace para vincular estas propiedades a los elementos de la interfaz de usuario sin establecerlos explícitamente. Un ejemplo de esto sería si tuvieras un StackPanel

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

Este XAML buscará las propiedades denominadas FirstName o LastName en el DataContext que se establece. Por lo tanto, al establecer DataContext en un objeto Person, puede mostrar los datos que especificamos.

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

Esto le dirá al StackPanel que complete esos dos cuadros de texto con 'Prueba' y 'Hombre'.

Esta lógica se extiende a cualquier tipo de objeto de IU, como SolidColorBrush para configurar colores. Si extendió la clase Person para aceptar una SolidColorBrush para una propiedad FavColor, entonces podría establecer el fondo del panel estableciendo un enlace para eso también, es decir

<StackPanel x:Name="MyStack" Background="{Binding FavColor}" Orientation="Horizontal">

Sin embargo, como se mencionó, realmente desea mantener sus modelos (los objetos que contienen los datos que desea mostrar, como nuestra Persona, un Usuario o una Forma, etc.) y cualquier tipo de información de Vista completamente separados. Para leer más sobre cómo hacer esto, buscaría en el patrón Model View View-Model (MVVM), que se centra principalmente en el enlace de datos XAML. Hay muchos buenos tutoriales por ahí, utilicé ejemplos de video para ayudarme a comprender, por lo que puede valer la pena buscarlos también para expandir sus conocimientos.

1
plusheen 27 jul. 2016 a las 14:35
Binding binding = new Binding();
binding.Path = new PropertyPath("FillProperty");
binding.Source = fillColor;
BindingOperations.SetBinding(hex.polygon, Polygon.FillProperty, binding);

Ese código crea un enlace cuyo Source es un SolidColorBrush y cuyo Path es FillProperty.

Lo que eso significa es que el enlace irá al objeto Source y buscará una propiedad llamada FillProperty en ese objeto Source, y luego pasará el valor de esa propiedad junto con la propiedad Fill de un polígono.

Eso no es lo que quieres: SolidColorBrush no tiene una propiedad llamada FillProperty (nada la tiene), y tampoco tiene una propiedad llamada Fill. Fill es la propiedad de destino, no la propiedad de origen. Lo que quieres es esto:

hex.polygon.Fill = fillColor;

No es útil usar un enlace en este caso particular, porque fillColor es una variable local. Utiliza enlaces para las propiedades, de modo que cuando la fuente cambie, el destino se actualizará (y / o los cambios de destino pueden actualizar el origen, según los parámetros).

Pero para aprender cómo funciona Binding, esto también debería hacer lo que quieres:

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

Veo cierta confusión sobre Polygon.FillProperty vs Polygon.Fill. Polygon.FillProperty es un objeto público estático de solo lectura DependencyProperty que describe las características de la propiedad de dependencia Fill del polígono. Polygon también tiene una propiedad regular llamada Fill, que puede usar directamente como lo mostré arriba. Es una convención que el nombre del objeto público DependencyProperty de solo lectura estático es el mismo que el de la propiedad de dependencia nocional, con un sufijo de "Propiedad", pero no es absolutamente necesario.

1
Community 23 may. 2017 a las 11:58