【WPF】自定义控件:ShellEditControl-同列单元格编辑支持文本框、下拉框和弹窗

news2025/4/16 1:51:03

需要实现表格同一列,单元格可以使用文本框直接输入编辑、下拉框选择和弹窗,文本框只能输入数字,弹窗中的数据是若干位的二进制值。

本文提供了两种实现单元格编辑状态下,不同编辑控件的方法:
1、DataTrigger控制控件的显示;
2、定义DataTemplateSelector选择器根据数据返回不同模板。

效果如下:
![[gif-ShellEditControl.gif]]

数据

行数据类定义

每行数据需要定义属性:

  • detail:string,描述
  • valueType:enum,值类型
  • setValue:object,设定值,需要定义成可更新属性(mvvm)
  • valueOptions:List<optionModel>,值类型为选项时,此属性有值
  • selectedOptionItem:optionModel,所选的元素,需要定义成可更新属性(mvvm)
  • childValues:ObservableCollection<ChildValueModel>,值类型为对象时,此属性有值
  • EditChildValueCommand:RelayCommand,编辑childValues发生弹窗事件按钮
  • editType:string/enum,修改类型,值为不可修改时单元格不可编辑
    定义方法
  • ParseValueToChildValue:setValue转childValues
public class GirdData : ObservableObject
{
	public string detail { get; set; }

	public ValueTypeEnum valueType { get; set; }
	
	private object _value;
	public object setValue
	{
	    get
	    {
	        return _value;
	    }
	    set
	    {
		    //弹窗数据,二进制 《---》 十进制
	        if (valueType == ValueTypeEnum.Object) 
	        childValues = ParseValueToChildValue(value, defaltChildValues);
	        //文本框数据,string <----> 数值
	        //value未填写时默认为“--”
	        if (valueType == ValueTypeEnum.Number 
	        && value.ToString() != "--")
	            try { 
	            //decimalPlaces小数点位数,类中应当有该属性,这里省略
	            value = Decimal.Round(Decimal
	            .Parse(value.ToString()), decimalPlaces); 
	            } catch { }
	        OnPropertyChanged(ref _value, value);
	    }
	}

	public List<OptionModel> valueOptions { get; set; }
	public OptionModel selectedOptionItem
	{
	    get
	    {
	        if (this.valueType != ValueTypeEnum.Option) return null;
	        //获取setValue对应的选项
	        if (setValue.ToString() == "--") return new OptionModel();
	        return valueOptions.Find(_ => _.optionValue.ToString() == setValue.ToString());
	    }
	    set
	    {
	        if (this.valueType != ValueTypeEnum.Option) return;
	        //获取选中选项的值
	        this.setValue = value.optionValue;
	    }
	}
	
	public ObservableCollection<ChildValueModel> childValues { get; set; }
	public RelayCommand EditChildValueCommand { get; set; }
	//十进制转二进制
	public ObservableCollection<ChildValueModel> ParseValueToChildValue(object oValue, ObservableCollection<ChildValueModel> childValues)
	{
	    return ParseValueToChildValue_static(oValue, childValues);
	}
	public static ObservableCollection<ChildValueModel> ParseValueToChildValue_static(object oValue, ObservableCollection<ChildValueModel> childValues)
	{
	    int value = int.Parse(oValue.ToString());
	    string sValues = Convert.ToString(value, 2);
	    if (sValues.Length > childValues.Count) return null;
	    sValues = sValues.PadLeft(childValues.Count, '0');
	    for (int i = 0; i < childValues.Count; i++)
	    {
	        childValues[childValues.Count - 1 - i].value = int.Parse(sValues[i].ToString());
	    }
	    return childValues;
	}
}
public enum ValueTypeEnum
{
    Number,
    Option,
    Object
}
//下拉框选项的类
public class OptionModel
{
    public int optionValue { get; set; }
    public string detail { get; set; }

    public override string ToString()
    {
        return fullDetail;
    }

	//页面中展示的选项及结果的字符串格式 值[描述]
    public string fullDetail
    {
        get
        {
            string res = optionValue + "[" + detail + "]";
            return detail == null ? "--" : res;
        }
    }
}
//弹窗中各位二进制对应类
public class ChildValueModel : ObservableObject, ICloneable
{
    public Action InvokeCollectionChangedAction;

    private object _value;

    public object value
    {
        get => _value;
        set
        {
            OnPropertyChanged(ref _value, value);
            //其中一位发生改变,对应的十进制发生变化,触发该事件
            InvokeCollectionChangedAction?.Invoke();
        }
    }
    public string propertyName { get; set; }

    public object Clone()
    {
        return new ChildValueModel
        {
            value = this.value,
            propertyName = this.propertyName
        };
    }
}

生成表格数据

写一些假数据,格式如下

new ObservableCollection<GirdDataModel>{
	new GirdData(){
		detail:**,
		valueType:ValueTypeEnum.**,
		setValue:**,//如“--”、1、23.432
		editType:**,
		//valueType==ValueTypeEnum.Option
		//如
		valueOptions = new List<OptionModel>
		{
		    new OptionModel{ optionValue=0,detail="正向"},
		    new OptionModel{ optionValue=1,detail="反向"}
		},
		//valueType==ValueTypeEnum.Object
		//如
		childValues = new ObservableCollection<ChildValueModel>
		{
		    new ChildValueModel{ propertyName="bit0",value=0},
		    new ChildValueModel{ propertyName="bit1",value=0},
		    new ChildValueModel{ propertyName="bit2",value=0},
		    new ChildValueModel{ propertyName="bit3",value=0},
		}
	},...
}

页面

表格页面

View

主要列包括

  • 描述 - detail
  • 设定值 - setValue
    <DataGridTemplateColumn.CellTemplate>自定义单元格未编辑时内容模板
  • 值类型为Option时,绑定selectedOptionItem,会自动调用ToString,显示格式:值[描述];
  • 值类型为其他时,绑定setValue;
    <DataGridTemplateColumn.CellEditingTemplate>自定义单元格编辑时内容模板
    提供两种实现不同值类型,单元格编辑方式不同的方法
1、DataTrigger控制控件的显示
  • 值类型为Number时,显示文本框,绑定setValue;
  • 值类型为Option时,显示下拉框,ItemsSource绑定valueOptions,SelectedItem绑定selectedOptionItem,下拉框元素模板本文绑定fullDetail,格式:值[描述];
  • 值类型为Object时,显示文本+详情按钮,文本绑定setValue,按钮绑定EditChildValueCommand(详细方法定义在VM中),并传值行全部数据。
<DataGrid ItemsSource="{Binding GridData,Mode=TwoWay}" 
          RowBackground="#E4FAF5"
          AlternatingRowBackground="#C8F0F0"
          CanUserAddRows="False"
          AutoGenerateColumns="False">
    <DataGrid.Columns>
	    <DataGridTextColumn Header="描述" Binding="{Binding detail,Mode=OneWay}" IsReadOnly="True"/>
		<DataGridTemplateColumn Header="设定值">
		    <DataGridTemplateColumn.CellTemplate>
		        <DataTemplate>
		            <Grid>
		                <TextBlock>
		                    <TextBlock.Style>
		                        <Style TargetType="TextBlock">
		                            <Setter Property="Text" Value="{Binding setValue,StringFormat=N0,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
		                            <Style.Triggers>
		                                <DataTrigger Binding="{Binding valueType}" Value="Option">
		                                    <Setter Property="Text" Value="{Binding selectedOptionItem}"/>
		                                </DataTrigger>
		                                <DataTrigger Binding="{Binding decimalPlaces}" Value="3">
		                                    <Setter Property="Text" Value="{Binding setValue,StringFormat=N3,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
		                                </DataTrigger>
		                            </Style.Triggers>
		                        </Style>
		                    </TextBlock.Style>
		                </TextBlock>
		            </Grid>
		        </DataTemplate>
		    </DataGridTemplateColumn.CellTemplate>
		    <DataGridTemplateColumn.CellEditingTemplate>
		        <DataTemplate>
		            <Grid>
		                <Grid.Resources>
		                    <Style TargetType="TextBox" x:Key="SetValueBox">
		                        <Setter Property="Text" Value="{Binding setValue,StringFormat=N0,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
		                        <Setter Property="Visibility" Value="Collapsed"/>
		                        <Setter Property="Template">
		                            <Setter.Value>
		                                <ControlTemplate>
		                                    <Grid>
		                                        <Rectangle StrokeThickness="1"/>
		                                        <TextBox Margin="1"
		                                             Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Text,Mode=TwoWay}"
		                                             BorderThickness="0"
		                                             Background="Transparent"
		                                             VerticalAlignment="Center"
		                                                 Foreground="WhiteSmoke"/>
		                                    </Grid>
		                                </ControlTemplate>
		                            </Setter.Value>
		                        </Setter>
		                        <Style.Triggers>
		                            <DataTrigger Binding="{Binding valueType}" Value="Number">
		                                <Setter Property="Visibility" Value="Visible"/>
		                            </DataTrigger>
		                            <DataTrigger Binding="{Binding decimalPlaces}" Value="3">
		                                <Setter Property="Text" Value="{Binding setValue,StringFormat=N3,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
		                            </DataTrigger>
		                        </Style.Triggers>
		                    </Style>
		                </Grid.Resources>
		                <TextBox Style="{StaticResource SetValueBox}"/>
		                <ComboBox ItemsSource="{Binding valueOptions}"
		                          SelectedItem="{Binding selectedOptionItem}">
		                    <ComboBox.Style>
		                        <Style TargetType="ComboBox">
		                            <Setter Property="Visibility" Value="Collapsed"/>
		                            <Style.Triggers>
		                                <DataTrigger Binding="{Binding valueType}" Value="Option">
		                                    <Setter Property="Visibility" Value="Visible"/>
		                                </DataTrigger>
		                            </Style.Triggers>
		                        </Style>
		                    </ComboBox.Style>
		                    <ComboBox.ItemTemplate>
		                        <DataTemplate>
		                            <TextBlock Text="{Binding fullDetail}"/>
		                        </DataTemplate>
		                    </ComboBox.ItemTemplate>
		                </ComboBox>
		                <Grid>
		                    <Grid.Style>
		                        <Style TargetType="Grid">
		                            <Setter Property="Visibility" Value="Collapsed"/>
		                            <Style.Triggers>
		                                <DataTrigger Binding="{Binding valueType}" Value="Object">
		                                    <Setter Property="Visibility" Value="Visible"/>
		                                </DataTrigger>
		                            </Style.Triggers>
		                        </Style>
		                    </Grid.Style>
		                    <TextBlock Text="{Binding setValue,Mode=TwoWay}"/>
		                    <Button Width="20" Content="..." HorizontalAlignment="Right"
		                            Command="{Binding EditChildValueCommand}"
		                            CommandParameter="{Binding}"/>
		                </Grid>
		            </Grid>
		        </DataTemplate>
		    </DataGridTemplateColumn.CellEditingTemplate>
		</DataGridTemplateColumn>
	</DataGrid.Columns>
</DataGrid>
2、定义DataTemplateSelector选择器

选择器可以根据值类型和修改类型,返回不同单元格编辑模板
选择器逻辑如下:

public class CellEditTemplateSelector : DataTemplateSelector
{
	public DataTemplate TextBoxTemplate { get; set; }
	public DataTemplate ComboxTemplate { get; set; }
	public DataTemplate PopupButtonTemplate { get; set; }
	public DataTemplate UnEnableTemplate { get; set; }
	public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container) {
		if (item is GirdDataModel) {
			GirdDataModel data = item as GirdDataModel;
			if (data.editType == "不可修改") return UnEnableTemplate;
			switch (data.valueType)
			{
				case ValueTypeEnum.Number:
					return TextBoxTemplate;
				case ValueTypeEnum.Option:
					return ComboxTemplate;
				case ValueTypeEnum.Object:
					return PopupButtonTemplate;
			}
		}
		return base.SelectTemplate(item, container);
	}
}

xaml中定义不同的单元格编辑模板,然后将选择器应用值CellEditingTemplateSelector属性。

<UserControl.Resources>
    <local:SetValueTextConverter x:Key="SetValueTextConverter"/>
    <local:SetValueTextEditingConverter x:Key="SetValueTextEditingConverter"/>
    <local:CellEditTemplateSelector x:Key="CellEditTemplateSelector">
        <local:CellEditTemplateSelector.TextBoxTemplate>
            <DataTemplate>
                <TextBox>
                    <TextBox.Text>
                        <MultiBinding Converter="{StaticResource SetValueTextEditingConverter}">
                            <Binding Path="setValue" UpdateSourceTrigger="PropertyChanged" />
                            <Binding Path="decimalPlaces"/>
                        </MultiBinding>
                    </TextBox.Text>
                </TextBox>
            </DataTemplate>
        </local:CellEditTemplateSelector.TextBoxTemplate>
        <local:CellEditTemplateSelector.ComboxTemplate>
            <DataTemplate>
                <ComboBox ItemsSource="{Binding valueOptions}"
                                      SelectedItem="{Binding selectedOptionItem}">
                    <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding fullDetail}"/>
                        </DataTemplate>
                    </ComboBox.ItemTemplate>
                </ComboBox>
            </DataTemplate>
        </local:CellEditTemplateSelector.ComboxTemplate>
        <local:CellEditTemplateSelector.PopupButtonTemplate>
            <DataTemplate>
                <Grid>
                    <TextBlock Text="{Binding setValue,Mode=TwoWay}"/>
                    <Button Width="20" Content="..." HorizontalAlignment="Right"
                            Command="{Binding EditChildValueCommand}"
                            CommandParameter="{Binding}"/>
                </Grid>
            </DataTemplate>
        </local:CellEditTemplateSelector.PopupButtonTemplate>
        <local:CellEditTemplateSelector.UnEnableTemplate>
            <DataTemplate>
                <TextBlock Text="--"/>
            </DataTemplate>
        </local:CellEditTemplateSelector.UnEnableTemplate>
    </local:CellEditTemplateSelector>
</UserControl.Resources>
...
<DataGrid ItemsSource="{Binding GridData,Mode=TwoWay}" 
          RowBackground="#E4FAF5"
          AlternatingRowBackground="#C8F0F0"
          CanUserAddRows="False"
          AutoGenerateColumns="False">
    <DataGrid.Columns>
	    <DataGridTextColumn Header="描述" Binding="{Binding detail,Mode=OneWay}" IsReadOnly="True"/>
		<DataGridTemplateColumn Header="设定值" 
		CellEditingTemplateSelector="{StaticResource CellEditTemplateSelector}">
		    <DataGridTemplateColumn.CellTemplate>
		        <DataTemplate>
		            <Grid>
		                <TextBlock>
		                    <TextBlock.Style>
		                        <Style TargetType="TextBlock">
		                            <Setter Property="Text" Value="{Binding setValue,StringFormat=N0,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
		                            <Style.Triggers>
		                                <DataTrigger Binding="{Binding valueType}" Value="Option">
		                                    <Setter Property="Text" Value="{Binding selectedOptionItem}"/>
		                                </DataTrigger>
		                                <DataTrigger Binding="{Binding decimalPlaces}" Value="3">
		                                    <Setter Property="Text" Value="{Binding setValue,StringFormat=N3,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
		                                </DataTrigger>
		                            </Style.Triggers>
		                        </Style>
		                    </TextBlock.Style>
		                </TextBlock>
		            </Grid>
		        </DataTemplate>
		    </DataGridTemplateColumn.CellTemplate>
		</DataGridTemplateColumn>
	</DataGrid.Columns>
</DataGrid>

ViewModel

private DataAccessForGrid dataAccessForGrid;
public ObservableCollection<GirdData> gridData { get; set; }
public ShellEditControl()
{
    dataAccessForGrid = new DataAccessForGrid();
    gridData = dataAccessForGrid.GetDataList();
    foreach (var _ in gridData)
    {
        if (_.valueType == ValueTypeEnum.Object)
        {
        //定义弹窗事件
            _.EditChildValueCommand = new RelayCommand((o) =>
            {
                ChildValueEditPopupOpen(_);
            });
        }
    }
}
//使用IOC模式打开弹窗
private void ChildValueEditPopupOpen(GirdData data)
{
    IChildValueEditPopupService service = IoC.Provide<IChildValueEditPopupService>();
    ChildValueEditPopupResult res = service.ChildValueEditPopupOpen(data);
    if (res.IsSuccess)
    {
        data.setValue = res.setValue;
    }
}

弹窗页面

View

主要内容:表格(ChildValues)和当前值(SetValue)

<Window x:Class="bueatifulApp.Components.DataGridWithEdit.View.ChildValuePopup"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:bueatifulApp.Components.DataGridWithEdit.View"
        mc:Ignorable="d"
        Title="写入参数" Height="313" Width="400"
        Background="#DADFEA" >
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="55"/>
            <RowDefinition/>
            <RowDefinition Height="30"/>
        </Grid.RowDefinitions>
        <Grid >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100"/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="25"/>
            </Grid.RowDefinitions>
            <TextBlock VerticalAlignment="Center" Text="描述" Grid.Column="0" Grid.Row="1"/>
            <TextBox Height="18" Text="{Binding Code}" IsEnabled="False" Grid.Column="1" Grid.Row="1"/>
        </Grid>
        <Grid Grid.Row="1">
            <DataGrid ItemsSource="{Binding ChildValues,Mode=TwoWay}" 
                      CanUserAddRows="False"
                      AutoGenerateColumns="False">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="属性名" Binding="{Binding propertyName,Mode=OneWay}" IsReadOnly="True"/>
                    <DataGridTextColumn Header="设定值" Binding="{Binding value,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
        <Grid Grid.Row="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="200"/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="70"/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <TextBlock VerticalAlignment="Center" Text="当前值"/>
                <TextBox Height="18" Text="{Binding SetValue,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Column="1"/>
            </Grid>
            <Grid Grid.Column="1" HorizontalAlignment="Right">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <Button Command="{Binding OKCommand}" Height="25" Width="60" Content="确定" Margin="0,0,10,0"/>
                <Button Command="{Binding CancelCommand}" Height="25" Width="60" Content="取消" Grid.Column="1"/>
            </Grid>
        </Grid>
    </Grid>
</Window>

ViewModel

public class ChildValueEditViewModel : ObservableObject
{
	private string code;//描述

	private ObservableCollection<ChildValueModel> childValues;//表格数据

	private object setValue;//设定值

	public string Code
	{
		get => this.code;
		set => OnPropertyChanged(ref code, value);
	}
	public ObservableCollection<ChildValueModel> ChildValues
	{
		get => this.childValues;
		set => OnPropertyChanged(ref childValues, value);

	}


	public object SetValue
	{
		get => this.setValue;
		set => OnPropertyChanged(ref setValue, value);
	}
}

public class ChildValueEditPopupViewModel : ChildValueEditViewModel
{
	public ICommand OKCommand { get; }
	public ICommand CancelCommand { get; }

	public IView View { get; }

	public ChildValueEditPopupViewModel(IView view)
	{
		this.View = view;

		this.OKCommand = new RelayCommand((o) => this.OkAction());
		this.CancelCommand = new RelayCommand((o) => this.CancelAction());
	}

	public void OkAction()
	{
		this.View.CloseDialog(true); // close it with a successful result
	}

	public void CancelAction()
	{
		this.View.CloseDialog(false); // close it with a failed result
	}
}

服务

定义窗口打开事件
定义窗口打开时接受的数据

服务接口
public interface IChildValueEditPopupService
{
    Task<ChildValueEditPopupResult> ChildValueEditPopupOpenAsync(GirdData data);

    ChildValueEditPopupResult ChildValueEditPopupOpen(GirdData data);
}
public class ChildValueEditPopupResult : ObservableObject
{
    public bool IsSuccess { get; set; }

    private object _setValue;

    public string code { get; set; }

    public object setValue { get=>_setValue; set=>OnPropertyChanged(ref _setValue,value); }
}
服务实现
internal class ChildValueEditPopupService : IChildValueEditPopupService
{
	public ChildValueEditPopupResult ChildValueEditPopupOpen(GirdData data)
	{
		var popup = new ChildValuePopup();
		popup.ViewModel.Code = data.detail;
		//需要深拷贝,才能正确修改大表数据
		popup.ViewModel.ChildValues = Copy.DeepCopy( data.childValues);

		foreach (var item in popup.ViewModel.ChildValues)
		{
		//定义大表设定值响应事件
			item.InvokeCollectionChangedAction = () => {
				popup.ViewModel.SetValue = GirdDataModel.ParseChildValues_static(popup.ViewModel.ChildValues);
			};
		}

		popup.ViewModel.SetValue = data.setValue;

		bool result = popup.ShowDialog() == true;
		if (!result) {
			return new ChildValueEditPopupResult() { IsSuccess = false};
		}

		return new ChildValueEditPopupResult()
		{
			IsSuccess = true,
			code = popup.ViewModel.Code,
			setValue = popup.ViewModel.SetValue,
		}; 
	}

	public async Task<ChildValueEditPopupResult> ChildValueEditPopupOpenAsync(GirdData data) {
		return await Application.Current.Dispatcher.InvokeAsync(() => {
			return ChildValueEditPopupOpen(data);
		});
	}
}
服务注册
 public partial class MainWindow : Window
 {
     public MainWindow()
     {
         InitializeComponent();
         IoC.Register<IChildValueEditPopupService>(new ChildValueEditPopupService());
     }
 }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2334777.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Seq2Seq - GRU补充讲解

nn.GRU 是 PyTorch 中实现门控循环单元&#xff08;Gated Recurrent Unit, GRU&#xff09;的模块。GRU 是一种循环神经网络&#xff08;RNN&#xff09;的变体&#xff0c;用于处理序列数据&#xff0c;能够更好地捕捉长距离依赖关系。 ⭐重点掌握输入输出部分输入张量&#…

从零开始学Python游戏编程19-游戏循环模式1

在《从零开始学Python游戏编程18-函数3》中提到&#xff0c;可以对游戏代码进行重构&#xff0c;把某些代码写入函数中&#xff0c;主程序再调用这些函数&#xff0c;这样使得代码程序更容易理解和维护。游戏循环模式实际上也是把代码写入到若干个函数中&#xff0c;通过循环的…

Java获取终端设备信息工具类

在很多场景中需要获取到终端设备的一些硬件信息等&#xff0c;获取的字段如下&#xff1a; 返回参数 参数含义备注systemName系统名称remoteIp公网iplocalIp本地ip取IPV4macmac地址去掉地址中的"-“或”:"进行记录cpuSerialcpu序列号hardSerial硬盘序列号drive盘符…

【Linux网络与网络编程】08.传输层协议 UDP

传输层协议负责将数据从发送端传输到接收端。 一、再谈端口号 端口号标识了一个主机上进行通信的不同的应用程序。在 TCP/IP 协议中&#xff0c;用 "源IP"&#xff0c;"源端口号"&#xff0c;"目的 IP"&#xff0c;"目的端口号"&…

没音响没耳机,把台式电脑声音播放到手机上

第一步&#xff0c;电脑端下载安装e2eSoft VSC虚拟声卡&#xff08;安装完成后关闭&#xff0c;不要点击和设置&#xff09; 第二步&#xff0c;电脑端下载安装&#xff08;SoundWire Server&#xff09;&#xff08;安装完成后不要关闭&#xff0c;保持默认配置&#xff09; 第…

XDocument和XmlDocument的区别及用法

因为这几天用到了不熟悉的xml统计数据&#xff0c;啃了网上的资料解决了问题&#xff0c;故总结下xml知识。 1.什么是XML?2.XDocument和XmlDocument的区别3.XDocument示例1示例2&#xff1a;示例3&#xff1a; 4.XmlDocument5.LINQ to XML6.XML序列化(Serialize)与反序列化(De…

Blender安装基础使用教程

本博客记录安装Blender和基础使用&#xff0c;可以按如下操作来绘制标靶场景、道路标识牌等。 目录 1.安装Blender 2.创建面板资源 步骤 1: 设置 Blender 场景 步骤 2: 创建一个平面 步骤 3: 将 PDF 转换为图像 步骤 4-方法1: 添加材质并贴图 步骤4-方法2&#xff1a;创…

【Git】从零开始使用git --- git 的基本使用

哪怕是野火焚烧&#xff0c;哪怕是冰霜覆盖&#xff0c; 依然是志向不改&#xff0c;依然是信念不衰。 --- 《悟空传》--- 从零开始使用git 了解 Gitgit创建本地仓库初步理解git结构版本回退 了解 Git 开发场景中&#xff0c;文档可能会经历若干版本的迭代。假如我们不进行…

Android 中支持旧版 API 的方法(API 30)

Android 中最新依赖库的版本支持 API 31 及以上版本&#xff0c;若要支持 API30&#xff0c;则对应的依赖库的版本就需要使用旧版本。 可通过修改模块级 build.gradle 文件来进行适配。 1、android 标签的 targetSdk 和 compileSdk 版本号 根据实际目标设备的 android 版本来…

[特殊字符] Hyperlane:Rust 高性能 HTTP 服务器库,开启 Web 服务新纪元!

&#x1f680; Hyperlane&#xff1a;Rust 高性能 HTTP 服务器库&#xff0c;开启 Web 服务新纪元&#xff01; &#x1f31f; 什么是 Hyperlane&#xff1f; Hyperlane 是一个基于 Rust 语言开发的轻量级、高性能 HTTP 服务器库&#xff0c;专为简化网络服务开发而设计。它支…

RIP V2路由协议配置实验CISCO

1.RIP V2简介&#xff1a; RIP V2&#xff08;Routing Information Protocol Version 2&#xff09;是 RIP 路由协议的第二版&#xff0c;属于距离矢量路由协议&#xff0c;主要用于中小型网络环境。相较于 RIP V1&#xff0c;RIP V2 在功能和性能上进行了多项改进&#xff0c…

《LNMP架构+Nextcloud私有云超维部署:量子级安全与跨域穿透实战》

项目实战-使用LNMP搭建私有云存储 准备工作 恢复快照&#xff0c;关闭安全软件 [rootserver ~]# setenforce 0[rootserver ~]# systemctl stop firewalld搭建LNMP环境 [rootserver ~]# yum install nginx mariadb-server php* -y# 并开启nginx服务并设置开机自启 [r…

3DMAX笔记-UV知识点和烘焙步骤

1. 在展UV时&#xff0c;如何点击模型&#xff0c;就能选中所有这个模型的uv 2. 分多张UV时&#xff0c;不同的UV的可以设置为不同的颜色&#xff0c;然后可以通过颜色进行筛选。 3. 烘焙步骤 摆放完UV后&#xff0c;要另存为一份文件&#xff0c;留作备份 将模型部件全部分成…

【新人系列】Golang 入门(十三):结构体 - 下

✍ 个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4dd; 专栏地址&#xff1a;https://blog.csdn.net/newin2020/category_12898955.html &#x1f4e3; 专栏定位&#xff1a;为 0 基础刚入门 Golang 的小伙伴提供详细的讲解&#xff0c;也欢迎大佬们…

Spring Boot 自定义商标(Logo)的完整示例及配置说明( banner.txt 文件和配置文件属性信息)

Spring Boot 自定义商标&#xff08;Logo&#xff09;的完整示例及配置说明 1. Spring Boot 商标&#xff08;Banner&#xff09;功能概述 Spring Boot 在启动时会显示一个 ASCII 艺术的商标 LOGO&#xff08;默认为 Spring 的标志&#xff09;。开发者可通过以下方式自定义&a…

Ubuntu虚拟机Linux系统入门

目录 一、安装 Ubuntu Linux 20.04系统 1.1 安装前准备工作 1.1.1 镜像下载 1.1.2 创建新的虚拟机 二、编译内核源码 2.1 下载源码 2.2 指定编译工具 2.3 将根文件系统放到源码根目录 2.4 配置生成.config 2.5 编译 三、安装aarch64交叉编译工具 四、安装QEMU 五、…

【蓝桥杯】2025省赛PythonB组复盘

前言 昨天蓝桥杯python省赛B组比完&#xff0c;今天在洛谷上估了下分&#xff0c;省一没有意外的话应该是稳了。这篇博文是对省赛试题的复盘&#xff0c;所给代码是省赛提交的代码。PB省赛洛谷题单 试题 A: 攻击次数 思路 这题目前有歧义&#xff0c;一个回合到底是只有一个…

【数据结构_4下篇】链表

一、链表的概念 链表&#xff0c;不要求在连续的内存空间&#xff0c;链表是一个离散的结构。 链表的元素和元素之间&#xff0c;内存是不连续的&#xff0c;而且这些元素的空间之间也没有什么规律&#xff1a; 1.顺序上没有规律 2.内存空间上也没有规律 *如何知道链表中包…

音视频 五 看书的笔记 MediaCodec

MediaCodec 用于访问底层媒体编解码器框架&#xff0c;编解码组件。通常与MediaExtractor(解封装,例如Mp4文件分解成 video和audio)、MediaSync、MediaMuxer(封装 例如音视频合成Mp4文件)、MediaCrypto、Image(cameraX 回调的ImageReader对象可以获取到Image帧图像,可转换成YU…

ubuntu 系统安装Mysql

安装 mysql sudo apt update sudo apt install mysql-server 启动服务 sudo systemctl start mysql 设置为开机自启 sudo systemctl enable mysql 查看服务状态 &#xff08;看到类似“active (running)”的状态信息代表成功&#xff09; sudo systemctl status mysql …