摘要:直接在控件上使用的 Trigger 只能使用 EventTrigger ,因此我們需要編寫能寫更多種類 Trigger 的 Style。} public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is double d) { return d >= Than。

響應式佈局在各種現代的 UI 框架中不是什麼新鮮的概念,基本都是內置支持。然而在古老的 WPF 框架中卻並沒有原生支持,後來雖然通過 Blend 自帶的 Interactions 庫實現了響應式佈局,但生成的代碼量太大了,而且需要引入額外的庫。

如果只是希望臨時局部地方使用響應式佈局,那麼其實可以直接使用 WPF 內置的綁定機制來完成響應式佈局。本文介紹如何使用。

思路是在控件尺寸發生變更的時候更新控件的樣式。而能容易實現這個的只有 TriggerSetter 那一套。直接在控件上使用的 Trigger 只能使用 EventTrigger ,因此我們需要編寫能寫更多種類 TriggerStyle

<Style x:Key="Style.Foo.WalterlvDemo">
    <Setter Property="Grid.Row" Value="0" />
    <Setter Property="Grid.Column" Value="0" />
    <Style.Triggers>
        <DataTrigger Value="True"
                     Binding="{Binding ActualHeight, ElementName=DemoWindow,
                              Converter={StaticResource GreaterOrEqualsConverter},
                              ConverterParameter=640}">
            <Setter Property="Grid.Row" Value="1" />
            <Setter Property="Grid.Column" Value="1" />
        </DataTrigger>
    </Style.Triggers>
</Style>

定義了一個樣式,默認情況下,行列是 (0, 0),當窗口寬度大於或等於 640 之後,行列換到 (1, 1)。

這裏我們需要一個大於或等於,以及小於的轉換器。

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace Cvte.EasiNote.UI.Styles.Converters
{
    public class GreaterOrEqualsConverter : IValueConverter
    {
        public double Than { get; set; }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is double d)
            {
                return d >= Than;
            }
            else if (value is float f)
            {
                return f >= Than;
            }
            else if (value is ulong ul)
            {
                return ul >= Than;
            }
            else if (value is long l)
            {
                return l >= Than;
            }
            else if (value is uint ui)
            {
                return ui >= Than;
            }
            else if (value is int i)
            {
                return i >= Than;
            }
            else if (value is ushort us)
            {
                return us >= Than;
            }
            else if (value is short s)
            {
                return s >= Than;
            }
            else
            {
                return false;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
public class LessConverter : IValueConverter
    {
        public double Than { get; set; }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is double d)
            {
                return d < Than;
            }
            else if (value is float f)
            {
                return f < Than;
            }
            else if (value is ulong ul)
            {
                return ul < Than;
            }
            else if (value is long l)
            {
                return l < Than;
            }
            else if (value is uint ui)
            {
                return ui < Than;
            }
            else if (value is int i)
            {
                return i < Than;
            }
            else if (value is ushort us)
            {
                return us < Than;
            }
            else if (value is short s)
            {
                return s < Than;
            }
            else
            {
                return false;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
}

如果你本身是寫的基礎控件的樣式,那麼綁定當然就跟本文一開始說的寫法非常類似了。

如果你需要寫的是一般控件,可以考慮直接在控件裏寫 <Framework.Style /> 把樣式內聯進去。

如果你寫的是 DataTemplate ,也一樣是使用 DataTrigger 綁定。

你也可以不綁定到窗口上,而綁定到控件本身上,使用 TemplatedParent 作爲綁定的源即可。

<DataTemplate>
    <DataTemplate.Resources>
        <local:LessConverter x:Key="LessThan60" Than="60" />
    </DataTemplate.Resources>
    <Grid>
        <Image x:Name="Icon" />
        <Rectangle x:Name="Mask" Fill="Red" />
    </Grid>
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource LessThan60}}" Value="True">
            <Setter TargetName="Icon" Property="Grid.ColumnSpan" Value="3" />
            <Setter TargetName="Mask" Property="Visibility" Value="Collapsed" />
        </DataTrigger>
</DataTemplate>

相關文章