将两个UserControl组合成两个状态的正确方法是什么? [英] What is the correct way to combine two UserControls into one with two states?

查看:80
本文介绍了将两个UserControl组合成两个状态的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经搜索了一下Internet和StackOverflow.为什么需要这个:我有两个UserControl分别称为PlusButtonMinusButton,它们都有通用的XAML和通用的代码隐藏.我想使用一个通用的基类,理想情况下,它也应具有XAML和代码隐藏功能.

I've searched the Internet and StackOverflow a little. Why I need this: I have two UserControls called PlusButton and MinusButton, and they have both common XAML and common code-behind. I want to use a common base class which ideally would also have XAML and code-behind.

我已经在此处看到了答案,但是我对XAML的经验不足,无法应用该解决方案.我很高兴能链接到官方文档页面,该页面向我学习了我需要执行的操作.我习惯于代码隐藏,因为我也使用WinForms,所以我不介意是否必须进行代码隐藏.

I have seen the answer posted here but I am not experienced in XAML enough to apply that solution. I would be happy with a link to an official documentation page that learns me what I need to do this. I am used to code-behind since I also use WinForms so I do not mind if I have to do code-behind.

我比XAML更容易理解代码背后的内容,因此我有很多代码背后的知识,在XAML中可能会做得更好.

I understand code-behind more easily than XAML so I have much code-behind that probably would have been done more nicely in XAML.

如果我使用发布的解决方案

If I use the solution posted here I get compiler errors:

  • cs_wpf_test_1.ArrowButton不能是XAML文件的根目录,因为它是使用XAML定义的.第1行的位置20.
  • 警告CS0108 PlusButton.InitializeComponent()隐藏继承的成员ArrowButton.InitializeComponent().如果打算隐藏,请使用new关键字.
  • cs_wpf_test_1.ArrowButton cannot be the root of a XAML file because it was defined using XAML. Line 1 Position 20.
  • Warning CS0108 PlusButton.InitializeComponent() hides inherited member ArrowButton.InitializeComponent(). Use the new keyword if hiding was intended.

我收到上面列出的两个编译器错误,并且我不知道什么是最正确的解决这些错误的方法.我希望它易于维护.

I get the two compiler errors listed above and I do not know what is the most correct walkaround to these errors. I would like it to be easily maintainable.

下面的代码是我遇到那些编译器错误之前的代码的版本.

The code below is a version of my code before I had those compiler errors.

<UserControl x:Class="cs_wpf_test_1.PlusButton"
             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" 
             xmlns:local="clr-namespace:cs_wpf_test_1"
             mc:Ignorable="d" 
             d:DesignHeight="120" d:DesignWidth="175"
             Loaded="UserControl_Loaded">
    <Button Name="MyButton" Focusable="False" Padding="0,0,0,0">
        <Button.Template>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border Background="{TemplateBinding Background}"
                         BorderBrush="{TemplateBinding BorderBrush}"
                         BorderThickness="{TemplateBinding BorderThickness}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates" CurrentStateChanged="CommonStates_CurrentStateChanged">
                            <VisualState x:Name="Normal" />
                            <VisualState x:Name="MouseOver" />
                            <VisualState x:Name="Pressed" />
                            <VisualState x:Name="Disabled" />
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
                        <Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                Name="MyCanvas">
                            <Polyline Stroke="Blue" Name="MyPolyline">
                                <Polyline.Points>
                                    <PointCollection>
                                        <Point X="5" Y="95" />
                                        <Point X="95" Y="95" />
                                        <Point X="50" Y="5" />
                                        <Point X="5" Y="95" />
                                    </PointCollection>
                                </Polyline.Points>
                            </Polyline>
                        </Canvas>
                        <Canvas HorizontalAlignment="Center" VerticalAlignment="Center"
                                Width="100" Height="100" Name="MySecondCanvas">
                            <Line Stroke="Black" X1="50" Y1="10"
                                  X2="50" Y2="90"
                  Name="MySignLine1" StrokeThickness="4"/>
                            <Line Stroke="Black" X1="10" Y1="50"
                                  X2="90" Y2="50"
                  Name="MySignLine2" StrokeThickness="4"/>
                        </Canvas>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Button.Template>
    </Button>
</UserControl>

PlusButton.xaml.cs

public partial class PlusButton : UserControl
{
    internal Polyline MyTemplatePolyline;
    internal Line MyTemplateSignLine1, MyTemplateSignLine2;
    internal Canvas MyTemplateCanvas,
        MyTemplateSecondCanvas;

    public PlusButton()
    {
        InitializeComponent();

        MyButton.Margin = new Thickness(
            -MyButton.BorderThickness.Left,
            -MyButton.BorderThickness.Top,
            -MyButton.BorderThickness.Right,
            -MyButton.BorderThickness.Bottom);
    }

    internal void SetPseudofocused(bool p)
    {
        if (p)
        {
            BorderBrush = Brushes.Blue;
        }
        else
        {
            BorderBrush = Brushes.Transparent;
        }
    }

    private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
        MyButton.ApplyTemplate();

        MyTemplatePolyline = (Polyline)MyButton.Template.FindName("MyPolyline", MyButton);
        MyTemplateSignLine1 = (Line)MyButton.Template.FindName("MySignLine1", MyButton);
        MyTemplateSignLine2 = (Line)MyButton.Template.FindName("MySignLine2", MyButton);
        MyTemplateCanvas = (Canvas)MyButton.Template.FindName("MyCanvas", MyButton);
        MyTemplateSecondCanvas = (Canvas)MyButton.Template.FindName("MySecondCanvas", MyButton);

        UpdateMyLayout();
    }

    private void CommonStates_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)
    {
        var btn = e.Control as Button;

        if (e.NewState.Name == "MouseOver")
        {
            btn.Background = Brushes.White;
        }
        else if (e.NewState.Name == "Pressed")
        {
            btn.Background = Brushes.LightBlue;
        }
        else if (e.NewState.Name == "Disabled")
        {
            btn.Background = Brushes.Gray;
        }
        else
        {
            btn.Background = (Brush)MyButton.FindResource(SystemColors.ControlBrushKey);
        }
    }

    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        base.OnPropertyChanged(e);

        if (e.Property == WidthProperty || e.Property == HeightProperty || e.Property == BorderThicknessProperty)
        {
            UpdateMyLayout();
        }
    }

    internal void UpdateMyLayout()
    {
        if (MyTemplateCanvas == null)
        {
            return;
        }

        MyTemplateCanvas.Height = Height;
        MyTemplateCanvas.Width = Width;

        double h = ActualHeight - BorderThickness.Top -
            BorderThickness.Bottom;
        double w = ActualWidth - BorderThickness.Left -
            BorderThickness.Right;

        MyTemplatePolyline.Points.Clear();
        MyTemplatePolyline.Points.Add(new Point(5, h - 5));
        MyTemplatePolyline.Points.Add(new Point(w - 5, h - 5));
        MyTemplatePolyline.Points.Add(new Point(w / 2, 5));
        MyTemplatePolyline.Points.Add(new Point(5, h - 5));

        h = MyTemplateSecondCanvas.ActualHeight;
        w = MyTemplateSecondCanvas.ActualWidth;

        double ltrbPadding = h / 3;

        double l1 = h - 2 * ltrbPadding;
        double l2 = w - 2 * ltrbPadding;

        double l = Math.Min(l1, l2);

        // draw a cross with two lines:
        MyTemplateSignLine1.X1 = l / 2d + ltrbPadding;
        MyTemplateSignLine1.X2 = l / 2d + ltrbPadding;
        MyTemplateSignLine1.Y1 = ltrbPadding;
        MyTemplateSignLine1.Y2 = l + ltrbPadding;

        MyTemplateSignLine2.X1 = ltrbPadding;
        MyTemplateSignLine2.X2 = l + ltrbPadding;
        MyTemplateSignLine2.Y1 = ltrbPadding + l / 2d;
        MyTemplateSignLine2.Y2 = ltrbPadding + l / 2d;

        // update focus border size:
        double v = ActualHeight / 25d;
        BorderThickness = new Thickness(v, v, v, v);
    }
}

MinusButton.xaml

与第一个XAML文件相同,但是MySecondCanvas的XAML仅包含一个Line.

MinusButton.xaml

The same as the first XAML file, but MySecondCanvas's XAML contains just one Line.

与第一个.cs文件相同,但是:

The same as the first .cs file, but:

  1. 它不创建或使用MyTemplateSignLine1MyTemplateSignLine2,它仅使用MyTemplateSignLine.
  2. MyTemplatePolyline包含其他看起来像向下箭头的点(第一个箭头,上下颠倒).
  3. MyTemplateSignLine与其他XAML文件中的MyTemplateSignLine2相似,并且位于代码后.
  1. It does not create or use the MyTemplateSignLine1 and MyTemplateSignLine2, it just uses MyTemplateSignLine.
  2. MyTemplatePolyline contains other points that look like a down arrow (the first arrow, turned upside-down).
  3. MyTemplateSignLine is just like MyTemplateSignLine2 from the other XAML file and code-behind.

推荐答案

下面的代码是将两个UserControl统一之后的.

The code below is after unifying the two UserControls.

我的XAML:

<UserControl x:Class="cs_wpf_test_1.ArrowButton"
             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" 
             xmlns:local="clr-namespace:cs_wpf_test_1"
             mc:Ignorable="d" 
             d:DesignHeight="120" d:DesignWidth="175"
             Loaded="UserControl_Loaded">
    <Button Name="MyButton" Focusable="False" Padding="0,0,0,0">
        <Button.Resources>
            <Style x:Key="styleWithPlusSign">
                <Style.Triggers>
                    <Trigger Property="Grid.Row" Value="0">
                        <Setter Property="Path.Data" Value="M 5,95 L 95,95 50,5 5,95"></Setter>
                    </Trigger>
                    <Trigger Property="Grid.Row" Value="1">
                        <Setter Property="Path.Data" Value="M 50,10 L 50,10 L 50,90 M 10,50 L 90,50"></Setter>
                    </Trigger>
                </Style.Triggers>
            </Style>
            <Style x:Key="styleWithMinusSign">
                <Style.Triggers>
                    <Trigger Property="Grid.Row" Value="0">
                        <Setter  Property="Path.Data" Value="M 5,5 L 50,50 95,5 5,5"></Setter>
                    </Trigger>
                    <Trigger Property="Grid.Row" Value="1">
                        <Setter Property="Path.Data" Value="M 10,50 L 90,50"></Setter>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Button.Resources>
        <Button.Template>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border Background="{TemplateBinding Background}"
                         BorderBrush="{TemplateBinding BorderBrush}"
                         BorderThickness="{TemplateBinding BorderThickness}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates" CurrentStateChanged="CommonStates_CurrentStateChanged">
                            <VisualState x:Name="Normal" />
                            <VisualState x:Name="MouseOver" />
                            <VisualState x:Name="Pressed" />
                            <VisualState x:Name="Disabled" />
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
                        <Path Stroke="Blue"
                              Stretch="Fill"
                              x:Name="MyFirstPath"
                              Style="{StaticResource styleWithPlusSign}"
                              Grid.Row="0"/>
                        <Path Stroke="Black"
                              StrokeThickness="1"
                              Stretch="Uniform"
                              x:Name="MySecondPath"
                              Style="{Binding ElementName=MyFirstPath, Path=Style}"
                              Grid.Row="1"/>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Button.Template>
    </Button>
</UserControl>

我的隐藏代码:

/// <summary>
/// Interaction logic for ArrowButton.xaml
/// </summary>
public partial class ArrowButton : UserControl
{
    internal Path MyTemplateSecondPath,
        MyTemplateFirstPath;

    public ArrowButton()
    {
        InitializeComponent();

        // TODO: use smth like MyButton.PropertyChanged to set this:
        MyButton.Margin = new Thickness(
            -MyButton.BorderThickness.Left,
            -MyButton.BorderThickness.Top,
            -MyButton.BorderThickness.Right,
            -MyButton.BorderThickness.Bottom);
    }

    public bool State
    {
        get
        {
            return (bool)GetValue(StateProperty);
        }
        set
        {
            SetValue(StateProperty, value);
        }
    }
    public static readonly DependencyProperty StateProperty =
        DependencyProperty.Register("State", typeof(bool),
            typeof(ArrowButton), new PropertyMetadata(true, new PropertyChangedCallback(OnStateChanged)));

    private static void OnStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var b = d as ArrowButton;

        b.MyButton.ApplyTemplate();

        b.MyTemplateFirstPath = (Path)b.MyButton.Template.FindName("MyFirstPath", b.MyButton);

        if (b.State)
        {
            // plus
            b.MyTemplateFirstPath.Style = b.MyButton.FindResource("styleWithPlusSign") as Style;
        }
        else
        {
            // minus
            b.MyTemplateFirstPath.Style = b.MyButton.FindResource("styleWithMinusSign") as Style;
        }
    }

    internal void SetPseudofocused(bool p)
    {
        if (p)
        {
            BorderBrush = Brushes.Blue;
        }
        else
        {
            BorderBrush = Brushes.Transparent;
        }
    }

    private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
        ApplyTemplate();

        MyTemplateSecondPath = (Path)MyButton.Template.FindName("MySecondPath", MyButton);

        UpdateMyLayout();
    }

    private void CommonStates_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)
    {
        var btn = e.Control as Button;

        if (e.NewState.Name == "MouseOver")
        {
            btn.Background = Brushes.White;
        }
        else if (e.NewState.Name == "Pressed")
        {
            btn.Background = Brushes.LightBlue;
        }
        else if (e.NewState.Name == "Disabled")
        {
            btn.Background = Brushes.Gray;
        }
        else
        {
            btn.Background = (Brush)MyButton.FindResource(SystemColors.ControlBrushKey);
        }
    }

    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        base.OnPropertyChanged(e);

        if (e.Property == WidthProperty ||
            e.Property == HeightProperty ||
            e.Property == BorderThicknessProperty)
        {
            UpdateMyLayout();
        }
    }

    internal void UpdateMyLayout()
    {
        if (MyTemplateSecondPath == null)
        {
            return;
        }

        // update focus border size:
        double v = ActualHeight / 25d;
        BorderThickness = new Thickness(v, v, v, v);

        double min = Math.Min(ActualWidth, ActualHeight);

        if (State)
        {
            MyTemplateSecondPath.Margin = new Thickness(
                min / 5,
                min / 5,
                min / 5,
                min / 5);
        }
        else
        {
            MyTemplateSecondPath.Margin = new Thickness(
                min / 2.2,
                min / 2.2,
                min / 2.2,
                min / 2.2);
        }
    }
}

这篇关于将两个UserControl组合成两个状态的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆