Winform:timer tick事件无法触发

情况描述

在其他的控件、对象事件中启用timer.Enable=true,但是事件触发了以后timer无法触发进入timer的tick事件中

原因分析

该控件、对象事件的进程在结束后,该事件进程销毁,同时timer开启的事件也会销毁,从而无法进入到timer的tick事件中。

解决办法

使用线程的方法来解决,重新开一个线程来执行timer控件的延时,可以使用委托方法进行解决。

  1. /// 同步委托
  2. this.Invoke(new MethodInvoker(delegate
  3. {
  4. timer1.Interval = 500;
  5. timer1.Start();
  6. }));
///异步委托
this.BeginInvoke(new MethodInvoker(delegate
            {

                timer1.Interval = Convert.ToInt32(CBox_Timer_Interval1.Text);//转换straing类型为int类型
                //timer1.Interval = 200;
                timer1.Start();
            }));

建议用异步委托的方法,如果这里采用同步委托的话,会造成委托的timer事件会抢占主线程事件,阻塞线程

WPF:调用线程无法访问此对象

情况描述

WPF多线程程序运行调试时报错:调用线程无法访问此对象,因为另一个线程拥有该对象

原因分析

有一个线程占着这个对象,当前线程无法再访问了。

解决办法

1.BeginInvoke()异步执行,不等待委托结束就更新;
2.Invoke()同步执行,需等待委托执行完。

YourControl.Dispatcher.BeginInvoke(new Action(delegate
    {
        //Do sth with Your Control
    }));
YourControl.Dispatcher.Invoke(new Action(delegate
    {
        //Do sth with Your Control
    }));

WPF:不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改

情况描述

报错信息:System.NotSupportedException:“该类型的 CollectionView 不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改。

原因分析

问题在WPF中的VM类中ObservableCollection类型,该类型的 CollectionView 不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改

解决办法

ThreadPool.QueueUserWorkItem(delegate
{
    SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(Application.Current.Dispatcher));
    SynchronizationContext.Current.Post(pl =>
    {
        //here write what you want to do
        //onlineHosts.Add(new HostInfo() { id = client.ID, ip = client.IP, isOnline = true });
    }, null);
});

WPF:Binding 判断值处理

需求描述

DataGrid、ListView等控件中某一个列绑定的是一个bool型的类成员,需要根据这个bool型的 true/false 显示 是/否等处理后的值

解决办法

三种方法:
1、传统的Binding方法,后台构造好数据,绑定就行。
2、转换器方法(Converter),绑定后,触发转换器,转换器负责把值转换成需要的内容。
3、DataTrigger方法,直接在xaml里面对数据进行处理,展示所需要的内容。
原解决方式页面不可访问,以第三种为例实现成功,代码如下:

<GridViewColumn Width="90" Header="状态">
  <GridViewColumn.CellTemplate>
    <DataTemplate>
      <TextBlock>
        <TextBlock.Style>
          <Style TargetType="TextBlock">
            <Style.Triggers>
              <DataTrigger Binding="{Binding Path=isOnline}" Value="False">
                <Setter Property="Text" Value="离线" />
                <Setter Property="Foreground" Value="Red" />
              </DataTrigger>
              <DataTrigger Binding="{Binding Path=isOnline}" Value="True">
                <Setter Property="Text" Value="在线" />
                <Setter Property="Foreground" Value="Green" />
              </DataTrigger>
            </Style.Triggers>
          </Style>
        </TextBlock.Style>
      </TextBlock>
    </DataTemplate>
  </GridViewColumn.CellTemplate>
</GridViewColumn>

根据绑定的isOnline值触发显示效果,如果为true,显示绿色字体的“在线”,false显示红色字体的“离线”

WPF:获取Label控件的Width问题

情况描述

如果Label控件未设定指定宽度,在程序中读取Label控件的宽度时,无论是label.Width,还是label.ActualWidth均存在问题(Width为NaN,ActualWidth不等于实际控件宽度

原因分析

Width:是我们期望控件应有的宽度,是可读写的,可在xaml文件中设置,也可在程序中设置。如果没有设置,Width的值为NaN(Not a Number)
ActualWidth:是控件Render的实际宽度,控件Render之前,它的值为0,。该属性是只读的。
Render相关内容没有了解的很详细,还没搞清楚这个的具体原因。

解决办法

lblMsg.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); 
Size s = lblMsg.DesiredSize;
MessageBox.Show($"label的宽度为{s.Width}");

WPF:SqlSugar UNIQUE constraint failed错误

情况描述

在使用SqlSugar进行sqlite数据库插入操作时,发生异常报错,错误内容为 UNIQUE constraint failed错误

原因分析

可能发生这种BUG的两种情况:
1:定义的字段为NOT NULL,而插入时对应的字段为NULL
2:定义的字段为PRIMARY,而插入时想插入的值已经在表中存在。
我的程序执行插入操作时未指定id值(已设定为自增),以为SqlSugar会自动插入,但是实际上没有,因为数据库表的实体类未指定NOT NULL 和PRIMARY 属性

解决办法

//using SqlSugar; 

[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int id { get; set; }

WPF:解决Stream Writer中文乱码问题

情况描述

使用Stream Writer写文件时,路径出现中文会乱码,使用new StreamWriter (path,Encoding.UTF8)同样不起作用

解决办法

在工具栏》NuGet包管理器》管理解决方案的NuGet程序包中,搜索 System.Text.Encoding.CodePages并安装,使用以下代码调用即可

Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
StreamReader sr = new StreamReader(fs, Encoding.GetEncoding("GB2312"));