动态模板wpf

时间:2011-11-28 10:24:48

标签: wpf xaml binding

我制作了一个如下所示的模板:

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

现在,它绑定到“Configuration”对象的属性BootSector(bool)。

我在我的窗口中使用此模板,该模板具有配置对象作为数据上下文,如下所示:

<Control Template="{StaticResource onoffValue}">

</Control>

效果很好,但我想更进一步。

我想知道如何将不同的属性传递给我的模板以动态绑定(动态更改模板绑定的属性) 即我试过像

这样的东西
<Control Template="{StaticResource onoffValue}" xmlns:test="{Binding Path=BootSector}"/>

并将其绑定在模板中以“测试”,但它不起作用

有可能吗?我怎样才能做到这一点 ?我想我离我不太远但不在那里!

提前谢谢

编辑:关于德米特里的回答:
    有一个错误使用它。当我这样做时:

<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。当我单击on按钮(true)时,它将bootSector设置为true,然后立即设置为false。行为应该是它保持为真,直到它被取消选中?这与此处相关的问题有关吗? http://geekswithblogs.net/claraoscura/archive/2008/10/17/125901.aspx

2 个答案:

答案 0 :(得分:1)

这里的想法是 - 通用行为从不复杂,通常不值得创建自定义控件。我承诺,实施可能会有所不同,但方法将保持不变。将XAML用于可以改变和编码的部分是有意义的,这些部分将保持不变。

更新1-使用自定义控件时,它变得更加容易。您不再需要附加属性 - 因为您将在自定义控件中获得专用空间,您也可以使用x:Name和GetTemplateChild(..)来对单个RadioButtons进行引用。

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

}

标记:

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

答案 1 :(得分:0)

您不应使用xmlns传递参数,而是使用Tag或模板ContentControl,然后您可以将Content绑定到您的媒体资源(设置)它到TwoWay)并在模板中使用TemplateBindingContent