wpf開源項目:wpf-controlbase

wpf開源項目:wpf-controlbase

倉庫readme很素,但看作者readme貼的幾篇博文居間,你會喜歡上它的

最后更新 2021/11/30 下午4:57
He BianGu
预计阅读 32 分钟
分类
WPF
专题
wpf控制項庫 wpf開源項目
标签
.NET WPF wpf開源項目 開源項目 開源

仓库截图

倉庫 readme 很素,但看作者 readme 貼的幾篇博文居間,你會喜歡上它的,廢話不多說,上居間目錄:

  1. 動畫封裝
https://blog.csdn.net/u010975589/article/details/95974854
  1. 屬性表單
https://blog.csdn.net/u010975589/article/details/95970200
  1. 消息對話
https://blog.csdn.net/u010975589/article/details/95985190
  1. 在 wpf 中應用 mvc
https://blog.csdn.net/u010975589/article/details/100019431
  1. 其他功能說明
https://blog.csdn.net/u010975589/article/details/103083605

下面詳細居間:

1. 動畫封裝

原文标题:示例:WPF中自定义StoryBoarService在代码中封装StoryBoard、Animation用于简化动画编写
原文链接:https://blog.csdn.net/u010975589/article/details/95974854

1.1目的:通過對 storyboard 和 animation 的封裝來簡化動畫的編寫

1.2示例

說明:漸隱藏是 wpf 中比較常用的動畫,上圖是通過 storyboarservice 封裝後的效果,在代碼中只要執行如下代碼即可:

DoubleStoryboardEngine.Create(1, 0, 1, "Opacity").Start(element);

上面的關閉效果可以定義一個命令如下:

public class CollapsedOfOpacityCommand : ICommand
{

    public bool CanExecute(object parameter) => true;

    public void Execute(object parameter)
    {
        if(parameter is UIElement element)
        {
            var engine = DoubleStoryboardEngine.Create(1, 0, 1, "Opacity");

            engine.Start(element);
        }
    }

    public event EventHandler CanExecuteChanged;
}

在 xaml 中調用如下命令即可完成關閉漸隱藏的效果

Command="{x:Static base:CommandService.CollapsedOfOpacityCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource
AncestorType=GroupBox}}"

傳入的 commandparmeter 將會在執行命令時漸隱藏

其中動畫效果的代碼只需一句代碼即可,簡化了動畫在代碼中繁瑣的編碼過程

DoubleStoryboardEngine.Create(1, 0, 1, "Opacity").Start(element);

1.3代碼:

目前只實現 doubleanimation 的封裝,後續將會對其他類型進行封裝

1.3.1 封閉修改基類

/// <summary> 动画引擎基类 </summary>
public abstract class StoryboardEngineBase : IDisposable
{
    protected Storyboard storyboard = new Storyboard();

    public EventHandler CompletedEvent { get; set; }

    public EasingFunctionBase Easing { get; set; } = EasingFunctionFactroy.PowerEase;

    public PropertyPath PropertyPath { get; set; }

    public Duration Duration { get; set; }

    public void Dispose()
    {
        storyboard.Completed -= CompletedEvent;
    }

    public abstract StoryboardEngineBase Start(UIElement element);

    public abstract StoryboardEngineBase Stop();

    public StoryboardEngineBase(int second, string property)
    {
        this.PropertyPath = new PropertyPath(property);
        this.Duration = new Duration(TimeSpan.FromSeconds(second));
    }

}

/// <summary> 动画泛型引擎基类 </summary>
public abstract class StoryboardEngineBase<T> : StoryboardEngineBase
{
    public StoryboardEngineBase(T from, T to, int second, string property) : base(second, property)
    {
        this.FromValue = from;
        this.ToValue = to;
    }

    public T FromValue { get; set; }

    public T ToValue { get; set; }

    //public RepeatBehavior RepeatBehavior { get; set; };

}

1.3.2 開放擴展 doublestoryboardengine

/// <summary> DoubleAnimation动画引擎 </summary>
public class DoubleStoryboardEngine : StoryboardEngineBase<double>
{
    public static DoubleStoryboardEngine Create(double from, double to, int second, string property)
    {
        return new DoubleStoryboardEngine(from, to, second, property);
    }

    public DoubleStoryboardEngine(double from, double to, int second, string property) : base(from, to, second, property)
    {

    }

    public override StoryboardEngineBase Start(UIElement element)
    {
        //  Do:时间线
        DoubleAnimation animation = new DoubleAnimation(1, 0, this.Duration);

        if (this.Easing != null)
            animation.EasingFunction = this.Easing;

        //if (this.RepeatBehavior != default(RepeatBehavior))
        //    animation.RepeatBehavior = (RepeatBehavior);

        //  Do:属性动画
        storyboard.Children.Add(animation);
        Storyboard.SetTarget(animation, element);
        Storyboard.SetTargetProperty(animation, this.PropertyPath);

        if (CompletedEvent != null)
            storyboard.Completed += CompletedEvent;
        storyboard.Begin();

        return this;
    }

    public override StoryboardEngineBase Stop()
    {
        this.storyboard.Stop();

        return this;
    }
}

1.3.3 過度效果工廠

/// <summary> 说明:https://docs.microsoft.com/zh-cn/dotnet/framework/wpf/graphics-multimedia/easing-functions </summary>
public static class EasingFunctionFactroy
{
    /// <summary> PowerEase:创建加速和/或减速使用的公式的动画f(t) = tp其中 p 等于Power属性。 </summary>
    public static PowerEase PowerEase { get; set; } = new PowerEase();
    /// <summary> BackEase:略微收回动画的动作,然后再开始进行动画处理指示的路径中。 </summary>
    public static BackEase BackEase { get; set; } = new BackEase();
    /// <summary> ElasticEase:创建类似于弹簧来回直到静止的动画 </summary>
    public static ElasticEase ElasticEase { get; set; } = new ElasticEase();
    /// <summary> BounceEase:创建弹跳效果。 </summary>
    public static BounceEase BounceEase { get; set; } = new BounceEase();
    /// <summary> CircleEase:创建加速和/或减速使用循环函数的动画。 </summary>
    public static CircleEase CircleEase { get; set; } = new CircleEase();

    /// <summary> QuadraticEase:创建加速和/或减速使用的公式的动画f(t) = t2。 </summary>
    public static QuadraticEase QuadraticEase { get; set; } = new QuadraticEase();

    /// <summary> CubicEase:创建加速和/或减速使用的公式的动画f(t) = t3。 </summary>
    public static CubicEase CubicEase { get; set; } = new CubicEase();
    /// <summary> QuarticEase:创建加速和/或减速使用的公式的动画f(t) = t4。 </summary>
    public static QuarticEase QuarticEase { get; set; } = new QuarticEase();
    /// <summary> QuinticEase:创建加速和/或减速使用的公式的动画f(t) = t5。 </summary>
    public static QuinticEase QuinticEase { get; set; } = new QuinticEase();

    /// <summary> ExponentialEase:创建加速和/或减速使用指数公式的动画。 </summary>
    public static ExponentialEase ExponentialEase { get; set; } = new ExponentialEase();

    /// <summary> SineEase:创建加速和/或减速使用正弦公式的动画。 </summary>
    public static SineEase SineEase { get; set; } = new SineEase();

}

1.3.4 使用方法

/// <summary> 构造方法 </summary>
/// <param name="from"> 起始值</param>
/// <param name="to"> 结束值  </param>
/// <param name="second"> 间隔时间秒 </param>
/// <param name="property"> 修改属性名称 </param>
///
public static DoubleStoryboardEngine Create(double from, double to, int second, string property)
{
    return new DoubleStoryboardEngine(from, to, second, property);
}

2. 屬性表單

原文标题:示例:WPF开发的简单ObjectProperyForm用来绑定实体表单
原文链接:https://blog.csdn.net/u010975589/article/details/95970200

2.1目的:自定義控制項,用來直接綁定實體數據,簡化開發周期

2.2實現

  1. 綁定實體對象
  2. 通過特性顯示屬性名稱
  3. 通過特性增加驗證條件
  4. 已經實現 string、int、double、datetime、bool 幾種簡單類型的 datatemplate 模板,其他模板支持擴展
  5. 其他後續更新...

2.3示例

實體定義如下:

public class Student
{
    [Display("姓名")]
    [Required]
    public string Name { get; set; }

    [Display("班级")]
    [Required]
    public string Class { get; set; }

    [Display("地址")]
    [Required]
    public string Address { get; set; }

    [Display("邮箱")]
    [Required]
    public string Emall { get; set; }

    [Display("可用")]
    [Required]
    public bool IsEnbled { get; set; }

    [Display("时间")]
    [Required]
    public DateTime time { get; set; }

    [Display("年龄")]
    [Required]
    public int Age { get; set; }

    [Display("平均分")]
    public double Score { get; set; }

    [Display("电话号码")]
    [Required]
    [RegularExpression(@"^1[3|4|5|7|8][0-9]{9}$", ErrorMessage = "手机号码不合法!")]
    public string Tel { get; set; }
}
  • displayattribute:用來標識顯示名稱
  • resuiredattribute:用來標識數據不能為空
  • rgularexpression:引用正則表達式驗證數據是否匹配
  • 其他特性後續更新...

應用方式:

<UserControl.Resources>
  <local:Student
    x:Key="S.Student.HeBianGu"
    Name="河边骨"
    Address="四川省成都市高新区"
    Class="四年级"
    Emall="7777777777@QQ.com"
    Age="33"
    Score="99.99"
    IsEnbled="True"
    time="2019-09-09"
  />
</UserControl.Resources>

<wpfcontrollib:ObjectPropertyForm
  Grid.Row="1"
  Title="学生信息"
  SelectObject="{StaticResource S.Student.HeBianGu}"
>
  <base:Interaction.Behaviors>
    <base:MouseDragElementBehavior ConstrainToParentBounds="True" />
    <base:SelectZIndexElementBehavior /> </base:Interaction.Behaviors
></wpfcontrollib:ObjectPropertyForm>

2.4代碼

2.4.1 通過反射獲取屬性和特性

ObservableCollection<ObjectPropertyItem> PropertyItemSource
{
    get { return (ObservableCollection<ObjectPropertyItem>)GetValue(PropertyItemSourceProperty); }
    set { SetValue(PropertyItemSourceProperty, value); }
}

// Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty PropertyItemSourceProperty =
    DependencyProperty.Register("PropertyItemSource", typeof(ObservableCollection<ObjectPropertyItem>), typeof(ObjectPropertyForm), new PropertyMetadata(new ObservableCollection<ObjectPropertyItem>(), (d, e) =>
      {
          ObjectPropertyForm control = d as ObjectPropertyForm;

          if (control == null) return;

          ObservableCollection<ObjectPropertyItem> config = e.NewValue as ObservableCollection<ObjectPropertyItem>;

      }));


void RefreshObject(object o)
{
    Type type = o.GetType();

    var propertys = type.GetProperties();

    this.PropertyItemSource.Clear();

    foreach (var item in propertys)
    {
        var from = ObjectPropertyFactory.Create(item, o);

        this.PropertyItemSource.Add(from);
    }

    this.ItemsSource = this.PropertyItemSource;
}

2.4.2 定義類型基類、擴展之類和工廠方法

/// <summary> 类型基类 </summary>
public class ObjectPropertyItem : NotifyPropertyChanged
{
    public string Name { get; set; }
    public PropertyInfo PropertyInfo { get; set; }

    public object Obj { get; set; }
    public ObjectPropertyItem(PropertyInfo property, object obj)
    {
        PropertyInfo = property;


        var display = property.GetCustomAttribute<DisplayAttribute>();

        Name = display == null ? property.Name : display.Name;

        Obj = obj;
    }


}

/// <summary> 泛型类型基类 </summary>
public class ObjectPropertyItem<T> : ObjectPropertyItem
{
    private T _value;
    /// <summary> 说明  </summary>
    public T Value
    {
        get { return _value; }
        set
        {

            this.Message = null;

            //  Do:检验数据有效性
            if (Validations != null)
            {
                foreach (var item in Validations)
                {
                    if (!item.IsValid(value))
                    {
                        this.Message = item.ErrorMessage;
                    }
                }
            }

            _value = value;

            RaisePropertyChanged("Value");

            this.SetValue(value);
        }
    }

    void SetValue(T value)
    {
        this.PropertyInfo.SetValue(Obj, value);
    }

    List<ValidationAttribute> Validations { get; }

    public ObjectPropertyItem(PropertyInfo property, object obj) : base(property, obj)
    {
        Value = (T)property.GetValue(obj);

        Validations = property.GetCustomAttributes<ValidationAttribute>()?.ToList();

        if(Validations!=null&& Validations.Count>0)
        {
            this.Flag = "*";
        }
    }



    private string _message;
    /// <summary> 说明  </summary>
    public string Message
    {
        get { return _message; }
        set
        {
            _message = value;
            RaisePropertyChanged("Message");
        }
    }

    public string Flag { get; set; }

}

/// <summary> 字符串属性类型 </summary>
public class StringPropertyItem : ObjectPropertyItem<string>
{
    public StringPropertyItem(PropertyInfo property, object obj) : base(property, obj)
    {
    }
}

/// <summary> 时间属性类型 </summary>
public class DateTimePropertyItem : ObjectPropertyItem<DateTime>
{
    public DateTimePropertyItem(PropertyInfo property, object obj) : base(property, obj)
    {
    }
}

/// <summary> Double属性类型 </summary>
public class DoublePropertyItem : ObjectPropertyItem<double>
{
    public DoublePropertyItem(PropertyInfo property, object obj) : base(property, obj)
    {
    }
}

/// <summary> Int属性类型 </summary>

public class IntPropertyItem : ObjectPropertyItem<int>
{
    public IntPropertyItem(PropertyInfo property, object obj) : base(property, obj)
    {
    }
}

/// <summary> Bool属性类型 </summary>
public class BoolPropertyItem : ObjectPropertyItem<bool>
{
    public BoolPropertyItem(PropertyInfo property, object obj) : base(property, obj)
    {
    }
}

類型工廠:

public class ObjectPropertyFactory
{
    public static ObjectPropertyItem Create(PropertyInfo info, object obj)
    {
        if (info.PropertyType == typeof(int))
        {
            return new IntPropertyItem(info, obj);
        }
        else if (info.PropertyType == typeof(string))
        {
            return new StringPropertyItem(info, obj);
        }
        else if (info.PropertyType == typeof(DateTime))
        {
            return new DateTimePropertyItem(info, obj);
        }
        else if (info.PropertyType == typeof(double))
        {
            return new DoublePropertyItem(info, obj);
        }
        else if (info.PropertyType == typeof(bool))
        {
            return new BoolPropertyItem(info, obj);
        }

        return null;
    }
}

2.4.3 樣式模板

<DataTemplate DataType="{x:Type base:StringPropertyItem}">
  <Grid
    Width="{Binding RelativeSource={RelativeSource AncestorType=local:ObjectPropertyForm},Path=Width-5}"
    Height="35"
    Margin="5,0"
  >
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="2*" />
      <ColumnDefinition Width="30" />
    </Grid.ColumnDefinitions>

    <TextBlock
      Text="{Binding Name}"
      FontSize="14"
      HorizontalAlignment="Center"
      VerticalAlignment="Center"
    />

    <TextBlock
      Text="{Binding Flag}"
      Grid.Column="1"
      Margin="5,0"
      FontSize="14"
      Foreground="{DynamicResource S.Brush.Red.Notice}"
      HorizontalAlignment="Right"
      VerticalAlignment="Center"
    />

    <local:FTextBox
      Text="{Binding Value,UpdateSourceTrigger=PropertyChanged}"
      Style="{DynamicResource DefaultTextBox}"
      FontSize="14"
      Width="Auto"
      CaretBrush="Black"
      Grid.Column="2"
      Height="30"
      base:ControlAttachProperty.FIcon=""
      VerticalContentAlignment="Center"
      HorizontalAlignment="Stretch"
      VerticalAlignment="Center"
    />

    <TextBlock
      Text="&#xe626;"
      Grid.Column="3"
      Style="{DynamicResource FIcon }"
      Foreground="{DynamicResource S.Brush.Red.Notice}"
      Visibility="{Binding Message,Converter={x:Static base:XConverter.VisibilityWithOutStringConverter},ConverterParameter={x:Null},Mode=TwoWay}"
      FontSize="14"
      TextTrimming="CharacterEllipsis"
      ToolTip="{Binding Message}"
      HorizontalAlignment="Center"
      VerticalAlignment="Center"
    />
  </Grid>
</DataTemplate>

<DataTemplate DataType="{x:Type base:BoolPropertyItem}">
  <Grid
    Width="{Binding RelativeSource={RelativeSource AncestorType=local:ObjectPropertyForm},Path=Width-5}"
    Height="35"
    Margin="5,0"
  >
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="2*" />
      <ColumnDefinition Width="30" />
    </Grid.ColumnDefinitions>

    <TextBlock
      Text="{Binding Name}"
      FontSize="14"
      HorizontalAlignment="Center"
      VerticalAlignment="Center"
    />

    <TextBlock
      Text="{Binding Flag}"
      Grid.Column="1"
      Margin="5,0"
      FontSize="14"
      Foreground="{DynamicResource S.Brush.Red.Notice}"
      HorizontalAlignment="Right"
      VerticalAlignment="Center"
    />
    <CheckBox
      IsChecked="{Binding Value}"
      FontSize="14"
      Grid.Column="2"
      Height="30"
      VerticalContentAlignment="Center"
      HorizontalAlignment="Left"
      VerticalAlignment="Center"
    />

    <TextBlock
      Text="&#xe626;"
      Grid.Column="3"
      Style="{DynamicResource FIcon }"
      Foreground="{DynamicResource S.Brush.Red.Notice}"
      Visibility="{Binding Message,Converter={x:Static base:XConverter.VisibilityWithOutStringConverter},ConverterParameter={x:Null}}"
      FontSize="14"
      TextTrimming="CharacterEllipsis"
      ToolTip="{Binding Message}"
      HorizontalAlignment="Center"
      VerticalAlignment="Center"
    />
  </Grid>
</DataTemplate>

<DataTemplate DataType="{x:Type base:DateTimePropertyItem}">
  <Grid
    Width="{Binding RelativeSource={RelativeSource AncestorType=local:ObjectPropertyForm},Path=Width-5}"
    Height="35"
    Margin="5,0"
  >
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="2*" />
      <ColumnDefinition Width="30" />
    </Grid.ColumnDefinitions>

    <TextBlock
      Text="{Binding Name}"
      FontSize="14"
      HorizontalAlignment="Center"
      VerticalAlignment="Center"
    />

    <TextBlock
      Text="{Binding Flag}"
      Grid.Column="1"
      Margin="5,0"
      FontSize="14"
      Foreground="{DynamicResource S.Brush.Red.Notice}"
      HorizontalAlignment="Right"
      VerticalAlignment="Center"
    />
    <DatePicker
      SelectedDate="{Binding Value}"
      FontSize="14"
      Grid.Column="2"
      Height="30"
      VerticalContentAlignment="Center"
      Width="Auto"
      HorizontalAlignment="Stretch"
      VerticalAlignment="Center"
    />

    <TextBlock
      Text="&#xe626;"
      Grid.Column="3"
      Style="{DynamicResource FIcon }"
      Foreground="{DynamicResource S.Brush.Red.Notice}"
      Visibility="{Binding Message,Converter={x:Static base:XConverter.VisibilityWithOutStringConverter},ConverterParameter={x:Null}}"
      FontSize="14"
      TextTrimming="CharacterEllipsis"
      ToolTip="{Binding Message}"
      HorizontalAlignment="Center"
      VerticalAlignment="Center"
    />
  </Grid>
</DataTemplate>

<DataTemplate DataType="{x:Type base:IntPropertyItem}">
  <Grid
    Width="{Binding RelativeSource={RelativeSource AncestorType=local:ObjectPropertyForm},Path=Width-5}"
    Height="35"
    Margin="5,0"
  >
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="2*" />
      <ColumnDefinition Width="30" />
    </Grid.ColumnDefinitions>

    <TextBlock
      Text="{Binding Name}"
      FontSize="14"
      HorizontalAlignment="Center"
      VerticalAlignment="Center"
    />

    <TextBlock
      Text="{Binding Flag}"
      Grid.Column="1"
      Margin="5,0"
      FontSize="14"
      Foreground="{DynamicResource S.Brush.Red.Notice}"
      HorizontalAlignment="Right"
      VerticalAlignment="Center"
    />
    <Slider
      Value="{Binding Value}"
      FontSize="14"
      Grid.Column="2"
      Height="30"
      VerticalContentAlignment="Center"
      HorizontalAlignment="Stretch"
      VerticalAlignment="Center"
    />

    <TextBlock
      Text="&#xe626;"
      Grid.Column="3"
      Style="{DynamicResource FIcon }"
      Foreground="{DynamicResource S.Brush.Red.Notice}"
      Visibility="{Binding Message,Converter={x:Static base:XConverter.VisibilityWithOutStringConverter},ConverterParameter={x:Null}}"
      FontSize="14"
      TextTrimming="CharacterEllipsis"
      ToolTip="{Binding Message}"
      HorizontalAlignment="Center"
      VerticalAlignment="Center"
    />
  </Grid>
</DataTemplate>

<DataTemplate DataType="{x:Type base:DoublePropertyItem}">
  <Grid
    Width="{Binding RelativeSource={RelativeSource AncestorType=local:ObjectPropertyForm},Path=Width-5}"
    Height="35"
    Margin="5,0"
  >
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="2*" />
      <ColumnDefinition Width="30" />
    </Grid.ColumnDefinitions>

    <TextBlock
      Text="{Binding Name}"
      FontSize="14"
      HorizontalAlignment="Center"
      VerticalAlignment="Center"
    />

    <TextBlock
      Text="{Binding Flag}"
      Grid.Column="1"
      Margin="5,0"
      FontSize="14"
      Foreground="{DynamicResource S.Brush.Red.Notice}"
      HorizontalAlignment="Right"
      VerticalAlignment="Center"
    />
    <Slider
      Value="{Binding Value}"
      FontSize="14"
      Grid.Column="2"
      Height="30"
      VerticalContentAlignment="Center"
      HorizontalAlignment="Stretch"
      VerticalAlignment="Center"
    />

    <TextBlock
      Text="&#xe626;"
      Grid.Column="3"
      Style="{DynamicResource FIcon }"
      Foreground="{DynamicResource S.Brush.Red.Notice}"
      Visibility="{Binding Message,Converter={x:Static base:XConverter.VisibilityWithOutStringConverter},ConverterParameter={x:Null}}"
      FontSize="14"
      TextTrimming="CharacterEllipsis"
      ToolTip="{Binding Message}"
      HorizontalAlignment="Center"
      VerticalAlignment="Center"
    />
  </Grid>
</DataTemplate>

<style TargetType="local:ObjectPropertyForm">
  <Setter Property="Background" Value="{DynamicResource S.Brush.TextBackgroud.Default}"/>
  <Setter Property="BorderThickness" Value="0"/>
  <!--<Setter Property="BorderBrush" Value="{x:Null}"/>-->
  <Setter Property="HorizontalAlignment" Value="Stretch"/>
  <Setter Property="VerticalAlignment" Value="Center"/>
  <Setter Property="HorizontalContentAlignment" Value="Center"/>
  <Setter Property="VerticalContentAlignment" Value="Center"/>
  <!--<Setter Property="FocusVisualStyle" Value="{x:Null}"/>-->
  <Setter Property="Padding" Value="0" />
  <Setter Property="Width" Value="500" />
  <Setter Property="Height" Value="Auto" />
  <Setter Property="ItemsSource" Value="{Binding PropertyItemSource,Mode=TwoWay}" />
  <Setter Property="ItemsPanel">
      <Setter.Value>
          <ItemsPanelTemplate>
              <StackPanel/>

          </ItemsPanelTemplate>
      </Setter.Value>
  </Setter>
  <Setter Property="Template">
      <Setter.Value>
          <ControlTemplate TargetType="local:ObjectPropertyForm">
              <GroupBox Header="{TemplateBinding Title}">
                  <Border HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
                      VerticalAlignment="{TemplateBinding VerticalAlignment}"
                      Background="{TemplateBinding Background}"
                      BorderBrush="{TemplateBinding BorderBrush}"
                      BorderThickness="{TemplateBinding BorderThickness}">
                      <ItemsPresenter/>
                  </Border>
              </GroupBox>
          </ControlTemplate>
      </Setter.Value>
  </Setter>
</style>

2.4.4 開放擴展

2.4.4.1 只需定義一個擴展類型,如:
/// <summary> 字符串属性类型 </summary>
public class StringPropertyItem : ObjectPropertyItem<string>
{
    public StringPropertyItem(PropertyInfo property, object obj) : base(property, obj)
    {
    }
}
2.4.4.2 再添加一個 datatmeplate,如:
<DataTemplate DataType="{x:Type base:StringPropertyItem}">
  <Grid
    Width="{Binding RelativeSource={RelativeSource AncestorType=local:ObjectPropertyForm},Path=Width-5}"
    Height="35"
    Margin="5,0"
  >
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="2*" />
      <ColumnDefinition Width="30" />
    </Grid.ColumnDefinitions>

    <TextBlock
      Text="{Binding Name}"
      FontSize="14"
      HorizontalAlignment="Center"
      VerticalAlignment="Center"
    />

    <TextBlock
      Text="{Binding Flag}"
      Grid.Column="1"
      Margin="5,0"
      FontSize="14"
      Foreground="{DynamicResource S.Brush.Red.Notice}"
      HorizontalAlignment="Right"
      VerticalAlignment="Center"
    />

    <local:FTextBox
      Text="{Binding Value,UpdateSourceTrigger=PropertyChanged}"
      Style="{DynamicResource DefaultTextBox}"
      FontSize="14"
      Width="Auto"
      CaretBrush="Black"
      Grid.Column="2"
      Height="30"
      base:ControlAttachProperty.FIcon=""
      VerticalContentAlignment="Center"
      HorizontalAlignment="Stretch"
      VerticalAlignment="Center"
    />

    <TextBlock
      Text="&#xe626;"
      Grid.Column="3"
      Style="{DynamicResource FIcon }"
      Foreground="{DynamicResource S.Brush.Red.Notice}"
      Visibility="{Binding Message,Converter={x:Static base:XConverter.VisibilityWithOutStringConverter},ConverterParameter={x:Null},Mode=TwoWay}"
      FontSize="14"
      TextTrimming="CharacterEllipsis"
      ToolTip="{Binding Message}"
      HorizontalAlignment="Center"
      VerticalAlignment="Center"
    />
  </Grid>
</DataTemplate>

3. 消息對話

原文标题:示例:WPF中自定义MessageService应用DialogHost、Snackbar、NotifyIcon显示各种场景提示消息
原文链接:https://blog.csdn.net/u010975589/article/details/95985190

3.1目的

不同交互場景需要提示不同的消息,不同的消息需要用不同的效果來展示,應用 dialoghost(對話框)、notifyicon(消息提示)、snackbar(氣泡消息)顯示各種場景提示消息,應用在 viewmodel 中

3.2實現

  1. 等待對話框
  2. 確定對話框
  3. 確定與取消對話框
  4. 百分比進度和文本進度對話框
  5. 氣泡提示消息(notifyicon)
  6. 提示消息(snackbar)

3.3示例

說明:

  1. 對話框:常規對話消息如上圖,等待對話框、消息對話、進度對話框;

(目前只封裝如上這幾種,自定義對話框只需創建用戶控制項調用通用加載方法即可,後續更新...)

  1. 提示消息:當進度保存成功是需要一個提示消息,顯示 2s 自動隱藏即可(如圖中友情提示部分分) ;

  2. 氣泡消息:當程式處於隱藏或某種狀態時需要應用氣泡提示消息;

3.4代碼

[ViewModel("Loyout")]
class LoyoutViewModel : MvcViewModelBase
{


    /// <summary> 命令通用方法 </summary>
    protected override async void RelayMethod(object obj)

    {
        string command = obj?.ToString();

        //  Do:对话消息
        if (command == "Button.ShowDialogMessage")
        {
            await MessageService.ShowSumitMessge("这是消息对话框?");

        }
        //  Do:等待消息
        else if (command == "Button.ShowWaittingMessge")
        {

            await MessageService.ShowWaittingMessge(() => Thread.Sleep(2000));

        }
        //  Do:百分比进度对话框
        else if (command == "Button.ShowPercentProgress")
        {
            Action<IPercentProgress> action = l =>
                {
                    for (int i = 0; i < 100; i++)
                    {
                        l.Value = i;

                        Thread.Sleep(50);
                    }

                    Thread.Sleep(1000);

                    MessageService.ShowSnackMessageWithNotice("加载完成!");
                };
            await MessageService.ShowPercentProgress(action);

        }
        //  Do:文本进度对话框
        else if (command == "Button.ShowStringProgress")
        {
            Action<IStringProgress> action = l =>
            {
                for (int i = 1; i <= 100; i++)
                {
                    l.MessageStr = $"正在提交当前页第{i}份数据,共100份";

                    Thread.Sleep(50);
                }

                Thread.Sleep(1000);

                MessageService.ShowSnackMessageWithNotice("提交完成:成功100条,失败0条!");
            };

            await MessageService.ShowStringProgress(action);

        }
        //  Do:确认取消对话框
        else if (command == "Button.ShowResultMessge")
        {
            Action<object, DialogClosingEventArgs> action = (l, k) =>
            {
                if ((bool)k.Parameter)
                {
                    MessageService.ShowSnackMessageWithNotice("你点击了取消");
                }
                else
                {
                    MessageService.ShowSnackMessageWithNotice("你点击了确定");
                }
            };

            MessageService.ShowResultMessge("确认要退出系统?", action);


        }
        //  Do:提示消息
        else if (command == "Button.ShowSnackMessage")
        {
            MessageService.ShowSnackMessageWithNotice("这是提示消息?");
        }
        //  Do:气泡消息
        else if (command == "Button.ShowNotifyMessage")
        {
            MessageService.ShowNotifyMessage("你有一条报警信息需要处理,请检查", "Notify By HeBianGu");
        }
    }
}

4. 在 wpf 中應用 mvc

原文标题:封装:简要介绍自定义开发基于WPF的MVC框架
原文链接:https://blog.csdn.net/u010975589/article/details/100019431

4.1目的

在使用 asp.net core 時,深感 mvc 框架作為頁面跳轉數據處理的方便,但 wpf 中似乎沒有現成的 mvc 框架,由此自定義開發一套 mvc 的框架,在使用過程中也體會到框架的優勢,下面簡要居間一下這套基於 mvvm 的 mvc 框架

4.2項目結構

主要有三部分组成:ControllerViewViewModel

其中 view 和 viewmodel 就是傳統 wpf 中的 mvvm 模式

不同地方在於頁面的跳轉應用到了 controller 做控制,如下示例 controller 的定義

4.3 controller 的結構和定義

4.3.1 定義 loyoutcontroller

[Route("Loyout")]
class LoyoutController : Controller
{

    public LoyoutController(ShareViewModel shareViewModel) : base(shareViewModel)
    {

    }

    public async Task<IActionResult> Center()
    {
        return View();
    }

    [Route("OverView/Button")]
    public async Task<IActionResult> Mdi()
    {
        return View();
    }

    public async Task<IActionResult> Left()
    {
        return View();
    }

    public async Task<IActionResult> Right()
    {
        return View();
    }

    public async Task<IActionResult> Top()
    {
        return View();
    }

    public async Task<IActionResult> Bottom()
    {
        return View();
    }

    [Route("OverView/Toggle")]
    public async Task<IActionResult> Toggle()
    {
        return View();
    }

    [Route("OverView/Carouse")]
    public async Task<IActionResult> Carouse()
    {
        return View();
    }

    [Route("OverView/Evaluate")]
    public async Task<IActionResult> Evaluate()
    {
        return View();
    }

    [Route("OverView/Expander")]
    public async Task<IActionResult> Expander()
    {
        return View();
    }

    [Route("OverView/Gif")]
    public async Task<IActionResult> Gif()
    {
        return View();
    }

    [Route("OverView/Message")]
    public async Task<IActionResult> Message()
    {
        return View();
    }

    [Route("OverView/Upgrade")]
    public async Task<IActionResult> Upgrade()
    {
        return View();
    }

    [Route("OverView/Property")]
    public async Task<IActionResult> Property()
    {
        return View();
    }

    [Route("OverView/ProgressBar")]
    public async Task<IActionResult> ProgressBar()
    {
        return View();
    }

    [Route("OverView/Slider")]
    public async Task<IActionResult> Slider()
    {
        return View();
    }

    [Route("OverView/Tab")]
    public async Task<IActionResult> Tab()
    {
        return View();
    }

    [Route("OverView/Tree")]
    public async Task<IActionResult> Tree()
    {
        return View();
    }

    [Route("OverView/Observable")]
    public async Task<IActionResult> Observable()
    {
        return View();
    }

    [Route("OverView/Brush")]
    public async Task<IActionResult> Brush()
    {
        return View();
    }

    [Route("OverView/Shadow")]
    public async Task<IActionResult> Shadow()
    {
        return View();
    }

    [Route("OverView/Button")]
    public async Task<IActionResult> Button()
    {
        await MessageService.ShowWaittingMessge(() => Thread.Sleep(500));

        this.ViewModel.ButtonContentText = DateTime.Now.ToString();

        return View();

    }



    [Route("OverView/Grid")]
    public async Task<IActionResult> Grid()
    {
        return View();
    }

    [Route("OverView/Combobox")]
    public async Task<IActionResult> Combobox()
    {
        return View();
    }

    [Route("OverView")]
    public async Task<IActionResult> OverView()
    {
        await MessageService.ShowWaittingMessge(() => Thread.Sleep(500));

        MessageService.ShowSnackMessageWithNotice("OverView");

        return View();
    }

    [Route("OverView/TextBox")]
    public async Task<IActionResult> TextBox()
    {
        return View();
    }

    [Route("OverView/Book")]
    public async Task<IActionResult> Book()
    {
        return View();
    }

    [Route("OverView/Xaml")]
    public async Task<IActionResult> Xaml()
    {
        return View();
    }

    [Route("OverView/Dimension")]
    public async Task<IActionResult> Dimension()
    {
        return View();
    }

    [Route("OverView/Geometry")]
    public async Task<IActionResult> Geometry()
    {
        return View();
    }

    [Route("OverView/Panel")]
    public async Task<IActionResult> Panel()
    {
        return View();
    }
    [Route("OverView/Transform3D")]
    public async Task<IActionResult> Transform3D()
    {
        return View();
    }

    [Route("OverView/Drawer")]
    public async Task<IActionResult> Drawer()
    {
        return View();
    }
}

4.3.2 前端的頁面

如下,其中紅色部分對應 controller 裡面的要跳轉的 route

如:选择了红色部分的 Button,首先会调用Button()方法,跳转到当前 Controller 对应的 View 文件加下的ButtonControl.xaml 页面

[Route("OverView/Button")]
public async Task<IActionResult> Button()
{
    await MessageService.ShowWaittingMessge(() => Thread.Sleep(500);

    this.ViewModel.ButtonContentText = DateTime.Now.ToString();

    return View();

}

可以在 button()方法中,寫一些業務邏輯,如對當前 viewmodel 的增刪改查等常規操作,其中當前 controller 成員 viewmodel 是內部封裝好的 viewmodel,對應 viewmodel 文件下面的當前 controller 的 viewmodel

4.3.3 示例

4.3.4 左側的 xaml 列表可以定義成如下形式

<Grid>
  <wpfcontrollib:LinkGroupExpander
    ScrollViewer.HorizontalScrollBarVisibility="Disabled"
    x:Name="selectloyout"
    SelectedLink="{Binding SelectLink,Mode=TwoWay}"
    Command="{x:Static wpfcontrollib:DrawerHost.CloseDrawerCommand}"
    CommandParameter="{x:Static Dock.Left}"
  >
    <wpfcontrollib:LinkActionGroup DisplayName="基础控件" Logo="&#xe69f;">
      <wpfcontrollib:LinkActionGroup.Links>
        <wpfcontrollib:LinkAction
          DisplayName="Button"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="Button"
        />
        <wpfcontrollib:LinkAction
          DisplayName="TextBox"
          Logo="&#xe6a3;"
          Controller="Loyout"
          Action="TextBox"
        />
        <wpfcontrollib:LinkAction
          DisplayName="Combobox"
          Logo="&#xe6a3;"
          Controller="Loyout"
          Action="Combobox"
        />
        <wpfcontrollib:LinkAction
          DisplayName="Toggle"
          Logo="&#xe6a3;"
          Controller="Loyout"
          Action="Toggle"
        />
        <wpfcontrollib:LinkAction
          DisplayName="Evaluate"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="Evaluate"
        />
        <wpfcontrollib:LinkAction
          DisplayName="Expander"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="Expander"
        />
        <wpfcontrollib:LinkAction
          DisplayName="Gif"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="Gif"
        />
        <wpfcontrollib:LinkAction
          DisplayName="ProgressBar"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="ProgressBar"
        />
        <wpfcontrollib:LinkAction
          DisplayName="Slider"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="Slider"
        />
      </wpfcontrollib:LinkActionGroup.Links>
    </wpfcontrollib:LinkActionGroup>

    <wpfcontrollib:LinkActionGroup DisplayName="布局控件" Logo="&#xe69f;">
      <wpfcontrollib:LinkActionGroup.Links>
        <wpfcontrollib:LinkAction
          DisplayName="MdiControl"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="Mdi"
        />
        <wpfcontrollib:LinkAction
          DisplayName="Carouse"
          Logo="&#xe69e;"
          Controller="Loyout"
          Action="Carouse"
        />
        <wpfcontrollib:LinkAction
          DisplayName="Tab"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="Tab"
        />
        <wpfcontrollib:LinkAction
          DisplayName="Tree"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="Tree"
        />
        <wpfcontrollib:LinkAction
          DisplayName="ObservableSource"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="Observable"
        />
        <wpfcontrollib:LinkAction
          DisplayName="Property"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="Property"
        />
        <wpfcontrollib:LinkAction
          DisplayName="Panel"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="Panel"
        />
      </wpfcontrollib:LinkActionGroup.Links>
    </wpfcontrollib:LinkActionGroup>

    <wpfcontrollib:LinkActionGroup DisplayName="全局控件" Logo="&#xe69f;">
      <wpfcontrollib:LinkActionGroup.Links>
        <wpfcontrollib:LinkAction
          DisplayName="Message"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="Message"
        />
        <wpfcontrollib:LinkAction
          DisplayName="Upgrade"
          Logo="&#xe69e;"
          Controller="Loyout"
          Action="Upgrade"
        />
        <wpfcontrollib:LinkAction
          DisplayName="Drawer"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="Drawer"
        />
      </wpfcontrollib:LinkActionGroup.Links>
    </wpfcontrollib:LinkActionGroup>

    <wpfcontrollib:LinkActionGroup DisplayName="全局样式" Logo="&#xe69f;">
      <wpfcontrollib:LinkActionGroup.Links>
        <wpfcontrollib:LinkAction
          DisplayName="Brush"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="Brush"
        />
        <wpfcontrollib:LinkAction
          DisplayName="Shadow"
          Logo="&#xe69f;"
          Controller="Loyout"
          Action="Shadow"
        />
      </wpfcontrollib:LinkActionGroup.Links>
    </wpfcontrollib:LinkActionGroup>
  </wpfcontrollib:LinkGroupExpander>
</Grid>

通過 linkgroupexpander 控制項,封裝 linkaction 去實現頁面的跳轉,其中只需要定義 linkaction 的幾個屬性即可達到跳轉到指定頁面的效果,如:

  • controller 屬性:用來指示要跳轉到哪個 controller
  • action 屬性:用來指示跳轉到哪個方法
  • displayname 屬性:在 ui 中顯示的名稱
  • logo 屬性:在 ui 中顯示的圖標

如下,controller 中的 button()方法對應的跳轉配置如下

[Route("OverView/Button")]
public async Task<IActionResult> Button()
<wpfcontrollib:LinkAction
  DisplayName="Button"
  Logo="&#xe69f;"
  Controller="Loyout"
  Action="Button"
/>

4.3.5 controller 基類的定義 controllerbase

主要方法是IActionResult View([CallerMemberName] string name = ""),这个方法是 MVC 实现的核心功能,主要通过反射去动态加载程序集,加载项目结构中的 View、ViewModel 去生成 IActionResult 返回给主页面进行页面跳转,代码如下:

public abstract class ControllerBase : IController
{
    protected virtual IActionResult View([CallerMemberName] string name = "")
    {
        var route = this.GetType().GetCustomAttributes(typeof(RouteAttribute), true).Cast<RouteAttribute>();

        string controlName = null;

        if (route.FirstOrDefault() == null)
        {
            controlName = this.GetType().Name;
        }
        else
        {
            controlName = route.FirstOrDefault().Name;
        }

        var ass = Assembly.GetEntryAssembly().GetName();

        string path = $"/{ass.Name};component/View/{controlName}/{name}Control.xaml";

        Uri uri = new Uri(path, UriKind.RelativeOrAbsolute);

        var content = Application.Current.Dispatcher.Invoke(() =>
        {
            return Application.LoadComponent(uri);
        });

        ActionResult result = new ActionResult();

        result.Uri = uri;
        result.View = content as ContentControl;

        Type type = Assembly.GetEntryAssembly().GetTypeOfMatch<NotifyPropertyChanged>(l => l.Name == controlName + "ViewModel");

        result.ViewModel = ServiceRegistry.Instance.GetInstance(type);

        Application.Current.Dispatcher.Invoke(() =>
        {
            (result.View as FrameworkElement).DataContext = result.ViewModel;

        });

        return result;
    }


    protected virtual IActionResult LinkAction([CallerMemberName] string name = "")
    {
        var route = this.GetType().GetCustomAttributes(typeof(RouteAttribute), true).Cast<RouteAttribute>();

        string controlName = null;

        if (route.FirstOrDefault() == null)
        {
            controlName = this.GetType().Name;
        }
        else
        {
            controlName = route.FirstOrDefault().Name;
        }

        var ass = Assembly.GetEntryAssembly().GetName();

        string path = $"/{ass.Name};component/View/{controlName}/{name}Control.xaml";

        Uri uri = new Uri(path, UriKind.RelativeOrAbsolute);

        var content = Application.Current.Dispatcher.Invoke(() =>
        {
            return Application.LoadComponent(uri);
        });

        ActionResult result = new ActionResult();

        result.Uri = uri;
        result.View = content;

        Type type = Assembly.GetEntryAssembly().GetTypeOfMatch<NotifyPropertyChanged>(l => l.Name == controlName + "ViewModel");

        result.ViewModel = ServiceRegistry.Instance.GetInstance(type);

        Application.Current.Dispatcher.Invoke(() =>
        {
            (result.View as FrameworkElement).DataContext = result.ViewModel;
        });

        return result;
    }

}

說明:

  1. 通過 application.loadcomponent(uri);來加載生成 control
  2. 通過反射 viewmodel 基類 notifypropertychanged 去找到對應 viewmodel,綁定到 view 中
  3. 將 view 和 viewmodel 封裝到 iactionresult 中返回給主頁面進行加載

其中 controller 中的方法返回類型是 async task,也就是整個頁面跳轉都是在異步中進行的,可以有效的避免頁面切換中的卡死效果

4.4 view 中的結構和定義

其中 view 在項目中的定義就是根據 controller 中的方法對應,在 mvc 中要嚴格按照結構定義[view/loyout],好處是可以減少代碼量,同時使格式統一代碼整齊,結構如下:

其中紅色 buttoncontrol.xaml 即是 controller 中 button()方法要跳轉的頁面,其他頁面同理

4.5 viewmodel 的結構和定義

其中 loyoutviewmodel 即是 loyoutcontroller 和整個 view/loyout 下所有頁面對應的 viewmodel

4.6整體 mvc 結構實現的效果如下

以上就是 mvc 應用在 wpf 中的簡要示例,具體內容和示例可從如下連結中下載代碼查看

代碼地址:https://github.com/HeBianGu/WPF-ControlBase.git

另一個應用 sqlite 資料庫的示例如下

代碼地址:https://github.com/HeBianGu/WPF-ExplorerManager.git

5. 其他功能說明

原文标题:示例:自定义WPF底层控件UI库 HeBianGu.General.WpfControlLib V2.0版本
原文链接:https://blog.csdn.net/u010975589/article/details/103083605

5.1目的

封裝了一些控制項到自定義的控制項庫中,方便快速開發

5.2實現功能

  • 基本實現常用基礎控制項,滿足常規軟體快速開發
  • 同時支持框架.net core 3.0 + ,.net framework 4.5+

5.3整體概況

5.3.1 登錄頁面

登錄頁面只需要繼承 loginwindowbase 基類,並且設置樣式 style=""即可

5.3.2 主頁面

主頁面只需繼承 linkwindowbase 基類,並且設置樣式 style=""即可

整體主窗口採用 viewbox 方式加載,當縮放窗口或應用到到其他解析度設備都會兼容

5.3.3 主題配置信息保存

主題配置信息已經封裝在 applicationbase 中,會自動在退出時保存設置好的配置信息(如:主題顏色、字體大小等)

總結: 應用此模式可以達到復用的目的,將通用部分封裝到底層,如需修改樣式只需修改 style 樣式文件或修改依賴屬性即可滿足功能修改

5.4主題設置

淺色主題示例如下:

深色主題示例如下圖:

主題設置功能主要包括:

  1. 設置主題主顏色

主題顏色主要用來標識要突出顯示的部分,目前可以選擇內置顏色、可以選擇跟隨系統主題顏色、可以自定義選擇顏色、可以使用動態主題(即設置主題每隔指定時間自動變化)

  1. 設置主題

主題目前實現四中主題,分別是淺色主題、深色主題、灰色主題、主顏色為主題

  1. 設置字體大小

字體大小目前內置兩種,分別是 large 和 small,其中這兩種顏色採用注入的方式加載,即可以在程式加載時設置著兩種字體的初始值

  1. 其他配置

包括中英文、設置標準行高等等可以在程式加載時進行初始化設置,這裡不做過多居間

**總結:**這樣設計的目的是審美因人而異,使用自定義配置的方式可以儘可能多的滿足多變的需求

5.5其他基礎控制項

5.5.1 數據表格

  • a 兼容主題字體和主題設置,後面將要提到的所有控制項均已應用主題設置,不做再說明
  • b 每頁顯示條數

可以設置每頁要顯示的條數

  • c 搜索

可以設置搜索過濾條件,包含指定搜索項的條目才會顯示

  • d 頁面跳轉

可以上一頁、下一頁、第一頁、最後一頁、指定頁

  • e 頁面信息

當前頁屬於數據源的第幾條至第幾條,數據源的總條目數

  • f 兩種風格的網格頁面

**總結:**以上功能封裝在控制項 pageddatagrid 中,只需綁定數據源即可實現以上功能,其中列印、導出等功能暫時沒有實現

5.5.2 樹形列表

  • a 支持按類別篩選

如上圖、選擇指定類型來過濾列表

  • b 支持按條件搜索

如上圖、輸入條件可以過濾指定條件

**總結:**使用方式為綁定數據源到 treelistview 控制項中

5.5.3 其他常用控制項

  • a 對話框

採用內置對話框,不是應用窗口,只是覆蓋層,可以避免窗口對話框引起的一些問題

  • b 對話窗口自定義對話窗口

相對系統對話窗口更美觀,增加顯示和隱藏效果,通過注入的方式可以自定義按鈕個數和功能

  • c 消息列表

目前有兩種模式,分別是在窗口內顯示和 window 系統中顯示,可以根據需求自定義顯示方式,示例如下

  • d 在線升級示例如下

  • e 導航菜單示例如下

  • f 其他功能包括

按鈕控制項、文本輸入框控制項、下拉列表控制項、數字控制項、日期選擇控制項、支持綁定的密碼框控制項、進度條控制項、拖動控制項、樹形控制項、分頁控制項以及其他自定義控制項。

以上控制項均已實現主題顏色、字體大小切換等,可以滿足常用軟體的功能

其中整體結構使用的自定義 mvc 方式加載,參考地址:https://blog.csdn.net/u010975589/article/details/100019431

由于控件过多不做详细介绍,有兴趣的可以下载源码或加载nuget包

5.6使用方式

nuget 包添加如下圖

說明:此示例部分功能部分代碼參考第三方框架,開源只應用於學習和參考,不做商用目的。

應用此框架的其他示例:

5.7下載地址

GitHub 下载地址:GitHub - HeBianGu/WPF-ControlBase: Wpf 封装的自定义控件资源库

安裝包示例下載地址:

更新:2019.12.16 增加.net core 3.0

目前已支持 core3.0 和.net 4.5 如有解決方案程式集無法加載請安裝這兩個框架

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 2025/1/26

wpf 藉助自定義 xml 文件實現國際化

本文詳細居間了在wpf程式中使用自定義xml文件實現國際化的方法,包括安裝必備nuget包、動態獲取語言列表、動態切換語言、在代碼和xaml界面中使用翻譯字符串等內容,同時提供了源碼連結,幫助開發者輕鬆實現wpf應用的國際化。

继续阅读