5

Composition of WPF controls

 3 years ago
source link: https://www.codesd.com/item/composition-of-wpf-controls.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Composition of WPF controls

advertisements

I want to create a WPF control that allows to manipulate specific bits in a Byte (the markup is attached to the bottom of this post).

It should be used as follows

<ns:BitManipulator BitByte={Binding Path=...} />

but I cannot figure out how to organise (Multi-)Bindings to keep the following three values the same: a) Byte-Value in the Model that BitByte will be bound to b) Byte-Value of BitByte which either should update its value if either the model's value or the BitVector's value changes c) Bit-Representation of BitByte in the TextBoxes named order_i

Any hint appreciated

XAML

<UserControl x:Class="WpfLib.StackOverflow.BitManipulator"
         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="300" d:DesignWidth="300">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <TextBox Name="order_0" Grid.Column="0" />
        <TextBox Name="order_1" Grid.Column="1" />
        <TextBox Name="order_2" Grid.Column="2" />
        <TextBox Name="order_3" Grid.Column="3" />
        <TextBox Name="order_4" Grid.Column="4" />
        <TextBox Name="order_5" Grid.Column="5" />
        <TextBox Name="order_6" Grid.Column="6" />
        <TextBox Name="order_8" Grid.Column="7" />
    </Grid>
</UserControl>

C# Code behind

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;

namespace WpfLib.StackOverflow
{
    [ContentProperty("BitByte")]
    public partial class BitManipulator : UserControl
    {
        public static DependencyProperty BitByteProperty =
            DependencyProperty.Register
            (
                "BitByte",
                typeof(Byte),
                typeof(BitManipulator),
                new PropertyMetadata(null)
            );

        public BitManipulator()
        {
            InitializeComponent();
        }

        public Byte BitByte
        {
            get { return (Byte)GetValue(BitByteProperty); }
            set { SetValue(BitByteProperty, value); }
        }
    }
}


Sorry for quite time. But it seems that there is mistake on MSDN at CollectionChanged event and it's not firing for individual items changes. For sketch of your case I'll just leave some sample. XAML for bindable collection of textboxes

<ItemsControl ItemsSource="{Binding Bits}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBox Text="{Binding Path=Value, UpdateSourceTrigger=PropertyChanged}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel IsItemsHost="True" Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

BindableBit class for individual items to fire changes to the upper level.

public class BindableBit : INotifyPropertyChanged {
        private int bit;
        private readonly int index;
        public Action<int, int> ChangedAction;

        public int Value {
            get { return bit; }
            set {
                bit = value;
                OnPropertyChanged();
                if (ChangedAction != null) ChangedAction(index, bit);
            }
        }

        public BindableBit(int index) {
            this.index = index;
        }

        ...PropertyChangedImplementation
    }

MainCode where we create base representation in bits and then change myByte value on every change from inside the collection.

public partial class MyCustomBitsControl: UserControl, INotifyPropertyChanged {
    private byte myByte;

    private readonly List<BindableBit> collection;
    public List<BindableBit> Bits {
        get { return collection; }
    }

    public MyCustomBitsControl() {
        const byte defaultValue = 7;
        myByte = defaultValue;
        var index = 0;
        collection = new BitArray(new[] { myByte }).Cast<bool>()
            .Select(b => new BindableBit(index++) { Value = (b ? 1 : 0), ChangedAction = ChangedAction }).Reverse().ToList();

        DataContext = this;
    }

    private void ChangedAction(int index, int value) {
        var bit = (byte)Math.Pow(2, index);
        if (value == 0) {
            myByte &= (byte)(byte.MaxValue - bit);
        }
        else {
            myByte |= bit;
        }
    }

    ...PropertyChangedImplementation
    }

After implementing dependency property you can get needed values from both the myByte field, or collection. Just reinitialize the collection on setValues like we've done in curent constructor. All changes will appear at UI(don't forget to notify for that change or modify its type to observableCollection).


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK