Динамический шаблон wpf - PullRequest
1 голос
/ 28 ноября 2011

Я создал шаблон, который выглядит следующим образом:

<ControlTemplate x:Key="onoffValue" TargetType="{x:Type Control}">
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Height="20" Margin="0,5,0,0">
                <RadioButton Content="On" Height="20" Name="On_radiobutton" />
                <RadioButton Content="Off" Height="20" Name="Off_radiobutton" Margin="20,0,0,0" />
            </StackPanel>
   <ControlTemplate.Triggers>
                <DataTrigger Binding="{Binding Path=BootSector}" Value="true">
                    <Setter TargetName="On_radiobutton" Property="IsChecked" Value="true"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=BootSector}" Value="false">
                    <Setter TargetName="Off_radiobutton" Property="IsChecked" Value="true"/>
                </DataTrigger>
   </ControlTemplate.Triggers>
</ControlTemplate>

На данный момент он привязан к свойству BootSector (bool) объекта «Конфигурация».

Я использую этошаблон в моем окне, в котором есть объект конфигурации в качестве контекста данных, например:

<Control Template="{StaticResource onoffValue}">

</Control>

Это прекрасно работает, но я хочу пойти дальше.

Я хотел бы знать, как я могу передатьдругое свойство в моем шаблоне для динамического связывания (динамическое изменение свойства, к которому привязан шаблон), т.е. я попробовал что-то вроде

<Control Template="{StaticResource onoffValue}" xmlns:test="{Binding Path=BootSector}"/>

и связал его в шаблоне с именем «test», но это не работает

Возможно ли это?Как я могу это сделать ?Я думаю, что я не слишком далеко, но еще не там!

Заранее спасибо

Редактировать: Относительно Дмитрия ответ:
Есть ошибка, использующая это.Когда я делаю:

<StackPanel local:ToggleControl.IsOn="{Binding BootSector, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                Grid.Row="0" Grid.Column="1"
        Orientation="Horizontal" HorizontalAlignment="Center" Margin="5">
                            <RadioButton Content="On" local:ToggleControl.Role="On"  Height="20" Margin="5" />
                            <RadioButton Content="Off" local:ToggleControl.Role="Off" Height="20" Margin="5" />
                        </StackPanel>  

По умолчанию BootSector на false.Когда я нажимаю на кнопку включения (true), он устанавливает bootSector в true, а затем сразу в false.Поведение должно быть таким, чтобы оно оставалось верным до тех пор, пока оно не будет проверено?Это связано с проблемой, связанной здесь?http://geekswithblogs.net/claraoscura/archive/2008/10/17/125901.aspx

Ответы [ 2 ]

1 голос
/ 28 ноября 2011

Здесь идея в том, что общее поведение никогда не бывает сложным и, как правило, не стоит создавать пользовательский элемент управления. Я предполагаю, что реализация может варьироваться, но подход останется прежним. Имеет смысл использовать XAML для частей, которые могут изменяться, и код для вещей, которые останутся постоянными.

ОБНОВЛЕНИЕ 1 - это становится еще проще при использовании пользовательских элементов управления. Вам больше не понадобится присоединенное свойство - поскольку вы получите выделенное для него пространство внутри своего пользовательского элемента управления, вы также можете использовать x: Name и GetTemplateChild (..), чтобы получить ссылку на отдельные кнопки RadioButton.

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace RadioButtons
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.Loaded += (o, e) =>
            {
                this.DataContext = new TwoBoolean()
                {
                    PropertyA = false,
                    PropertyB = true
                };
            };
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(((TwoBoolean)this.DataContext).ToString());
        }
    }

    public enum RadioButtonRole
    { 
        On,
        Off
    }


    public class ToggleControl : DependencyObject
    {
        public static readonly DependencyProperty IsOnProperty =
            DependencyProperty.RegisterAttached("IsOn",
            typeof(bool?),
            typeof(ToggleControl),
            new PropertyMetadata(null, 
                new PropertyChangedCallback((o, e) => 
                {
                    ToggleControl.OnIsOnChanged((Panel)o, (bool)e.NewValue);
                })));


        public static readonly DependencyProperty RoleProperty =
            DependencyProperty.RegisterAttached("Role",
            typeof(RadioButtonRole?),
            typeof(ToggleControl),
            new PropertyMetadata(null,
                new PropertyChangedCallback((o, e) =>
                {

                })));

        private static readonly DependencyProperty IsSetUpProperty =
            DependencyProperty.RegisterAttached("IsSetUp",
            typeof(bool),
            typeof(ToggleControl),
            new PropertyMetadata(false));

        private static void OnIsOnChanged(Panel panel, bool e)
        {
            if (!ToggleControl.IsSetup(panel))
            {
                ToggleControl.Setup(panel);
            }

            RadioButtonRole role;

            if (e)
            {
                role = RadioButtonRole.On;
            }
            else
            {
                role = RadioButtonRole.Off;
            }

            ToggleControl.GetRadioButtonByRole(role, panel).IsChecked = true;
        }

        private static void Setup(Panel panel)
        {
            // get buttons
            foreach (RadioButton radioButton in
                new RadioButtonRole[2]
                {
                    RadioButtonRole.On, 
                    RadioButtonRole.Off
                }.Select(t =>
                    ToggleControl.GetRadioButtonByRole(t, panel)))
            {
                radioButton.Checked += (o2, e2) => 
                {
                    RadioButton checkedRadioButton = (RadioButton)o2;

                    panel.SetValue(ToggleControl.IsOnProperty, 
                        ToggleControl.GetRadioButtonRole(checkedRadioButton) == RadioButtonRole.On);
                };
            }

            panel.SetValue(ToggleControl.IsSetUpProperty, true);
        }

        private static bool IsSetup(Panel o)
        {
            return (bool)o.GetValue(ToggleControl.IsSetUpProperty);
        }

        private static RadioButton GetRadioButtonByRole(RadioButtonRole role,
            Panel container)
        {
            return container.Children.OfType<RadioButton>().First(t => 
                (RadioButtonRole)t.GetValue(ToggleControl.RoleProperty) == role);
        }

        private static RadioButtonRole GetRadioButtonRole(RadioButton radioButton)
        {
            return (RadioButtonRole)radioButton.GetValue(ToggleControl.RoleProperty);
        }

        public static void SetIsOn(DependencyObject o, bool? e)
        {
            o.SetValue(ToggleControl.IsOnProperty, e);
        }

        public static bool? GetIsOn(DependencyObject e)
        {
            return (bool?)e.GetValue(ToggleControl.IsOnProperty);
        }

        public static void SetRole(DependencyObject o, RadioButtonRole? e)
        {
            o.SetValue(ToggleControl.RoleProperty, e);
        }

        public static RadioButtonRole? GetRole(DependencyObject e)
        {
            return (RadioButtonRole?)e.GetValue(ToggleControl.RoleProperty);
        }
    }

    public class TwoBoolean: INotifyPropertyChanged
    {
        private bool propertyA, propertyB;

        public bool PropertyA
        {
            get
            {
                return this.propertyA;
            }
            set
            {
                this.propertyA = value;

                this.OnPropertyChanged("PropertyA");
            }
        }

        public bool PropertyB
        {
            get
            {
                return this.propertyB;
            }
            set
            {
                this.propertyB = value;

                this.OnPropertyChanged("PropertyB");
            }
        }

        private void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, 
                    new PropertyChangedEventArgs(propertyName));
            }
        }

        public override string ToString()
        {
            return string.Format("PropertyA:{0}, PropertyB:{1}", this.PropertyA, this.PropertyB);
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

}

Markup:

<Window x:Class="RadioButtons.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:RadioButtons"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0" Margin="5" VerticalAlignment="Center">PropertyA</TextBlock>
        <StackPanel local:ToggleControl.IsOn="{Binding PropertyA, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                    Grid.Row="0" Grid.Column="1"
            Orientation="Horizontal" HorizontalAlignment="Center" Margin="5">
            <RadioButton Content="On" local:ToggleControl.Role="On"  Height="20" Margin="5" />
            <RadioButton Content="Off" local:ToggleControl.Role="Off" Height="20" Margin="5" />
        </StackPanel>

        <TextBlock Grid.Row="1" Grid.Column="0" Margin="5" VerticalAlignment="Center">PropertyB</TextBlock>
        <StackPanel local:ToggleControl.IsOn="{Binding PropertyB, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                    Grid.Row="1" Grid.Column="1"
            Orientation="Horizontal" HorizontalAlignment="Center" Margin="5">
            <RadioButton Content="On" local:ToggleControl.Role="On"  Height="20"  Margin="5" />
            <RadioButton Content="Off" local:ToggleControl.Role="Off" Height="20" Margin="5" />
        </StackPanel>
        <Button Click="Button_Click" Grid.Row="3" Grid.ColumnSpan="2">Save</Button>
    </Grid>
</Window>
0 голосов
/ 28 ноября 2011

Вы не должны использовать xmlns для передачи параметра, вместо этого используйте Tag или шаблон ContentControl, тогда вы можете связать Content со своим свойством (установите его на TwoWay) и использоватьTemplateBinding до Content внутри шаблона.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...