我有一个使用ComboBox的WPF应用程序。我的ComboBox ItemSource绑定到一个List <>
,我在后台从C#中填充它。
下面是该C#的List<>
代码:
// Main code
List<AudioDevice> devices = new List<AudioDevice>();
HRESULT hr = HRESULT.E_FAIL;
Guid CLSID_MMDeviceEnumerator = new Guid("{BCDE0395-E52F-467C-8E3D-C4579291692E}");
Type MMDeviceEnumeratorType = Type.GetTypeFromCLSID(CLSID_MMDeviceEnumerator, true);
object MMDeviceEnumerator = Activator.CreateInstance(MMDeviceEnumeratorType);
IMMDeviceEnumerator pMMDeviceEnumerator = (IMMDeviceEnumerator)MMDeviceEnumerator;
if (pMMDeviceEnumerator != null)
{
string sIdDefaultRender = null;
string sIdDefaultCapture = null;
IMMDevice pDefaultDevice = null;
hr = pMMDeviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eConsole, out pDefaultDevice);
if (hr == HRESULT.S_OK)
{
IntPtr hGlobal = Marshal.AllocHGlobal(260);
hr = pDefaultDevice.GetId(out hGlobal);
sIdDefaultRender = Marshal.PtrToStringUni(hGlobal);
Marshal.FreeHGlobal(hGlobal);
Marshal.ReleaseComObject(pDefaultDevice);
}
hr = pMMDeviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eCapture, ERole.eConsole, out pDefaultDevice);
if (hr == HRESULT.S_OK)
{
IntPtr hGlobal = Marshal.AllocHGlobal(260);
hr = pDefaultDevice.GetId(out hGlobal);
sIdDefaultCapture = Marshal.PtrToStringUni(hGlobal);
Marshal.FreeHGlobal(hGlobal);
Marshal.ReleaseComObject(pDefaultDevice);
}
IMMDeviceCollection pDeviceCollection = null;
hr = pMMDeviceEnumerator.EnumAudioEndpoints(EDataFlow.eAll, DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED, out pDeviceCollection);
if (hr == HRESULT.S_OK)
{
uint nDevices = 0;
hr = pDeviceCollection.GetCount(out nDevices);
devices.Add(new AudioDevice() { Name = "System default", Direction = "Playback", Id = sIdDefaultRender, Default = true });
for (uint i = 0; i < nDevices; i++)
{
IMMDevice pDevice = null;
hr = pDeviceCollection.Item(i, out pDevice);
if (hr == HRESULT.S_OK)
{
IPropertyStore pPropertyStore = null;
hr = pDevice.OpenPropertyStore(STGM_READ, out pPropertyStore);
if (hr == HRESULT.S_OK)
{
string sFriendlyName = null;
string sDesc = null;
PROPVARIANT pv = new PROPVARIANT();
hr = pPropertyStore.GetValue(ref PKEY_Device_FriendlyName, out pv);
if (hr == HRESULT.S_OK)
{
sFriendlyName = Marshal.PtrToStringUni(pv.pwszVal);
}
hr = pPropertyStore.GetValue(ref PKEY_Device_DeviceDesc, out pv);
if (hr == HRESULT.S_OK)
{
sDesc = Marshal.PtrToStringUni(pv.pwszVal);
}
IntPtr hGlobal = Marshal.AllocHGlobal(260);
hr = pDevice.GetId(out hGlobal);
string sId = Marshal.PtrToStringUni(hGlobal);
Marshal.FreeHGlobal(hGlobal);
IMMEndpoint pEndpoint = null;
pEndpoint = (IMMEndpoint)pDevice;
EDataFlow eDirection = EDataFlow.eAll;
hr = pEndpoint.GetDataFlow(out eDirection);
//System.Diagnostics.Trace.WriteLine("\tDirection : " + eDirection.ToString());
string sDirection = "";
if (eDirection == EDataFlow.eRender)
sDirection = "Playback";
else if (eDirection == EDataFlow.eCapture)
sDirection = "Recording";
int nState = 0;
hr = pDevice.GetState(out nState);
if ((nState == DEVICE_STATE_ACTIVE))
{
devices.Add(new AudioDevice() { Name = sFriendlyName, Direction = sDirection, Id = sId, Default = (sId == sIdDefaultRender || (sId == sIdDefaultCapture)) });
//sFriendlyName += (sId == sIdDefaultRender || sId == sIdDefaultCapture) ? " (System default)" : "";
//devices.Add(new AudioDevice() { Name = sFriendlyName, Direction = sDirection, Default = (sId == sIdDefaultRender || (sId == sIdDefaultCapture)) });
////devices.Add(new AudioDevice() { Name = sFriendlyName, Direction = sDirection, Default = (sId == sIdDefaultRender || (sId == sIdDefaultCapture)) });
}
Marshal.ReleaseComObject(pPropertyStore);
}
Marshal.ReleaseComObject(pDevice);
}
}
devices.Insert(devices.Count - 0, new AudioDevice() { Name = "Selected application ...", Direction = "Recording", Id = "Idlast", Default = false });
}
Marshal.ReleaseComObject(pDeviceCollection);
ListCollectionView lcv = new ListCollectionView(devices);
lcv.GroupDescriptions.Add(new PropertyGroupDescription("Direction"));
this.cmb1.ItemsSource = lcv;
}
}
public class AudioDevice
{
public string Name { get; set; }
public string Direction { get; set; }
public string Id { get; set; }
public bool Default { get; set; }
public override string ToString()
{
return Name;
}
}
实际上,我可以使用此代码检索默认可用的音频设备,尽管这段代码是一个Gem,但您可以在您的个人项目中使用此代码。
如果您仔细查看代码,那么您将看到这一行this.cmb1.ItemsSource = lcv;
,这意味着List<>
被添加为ComboBox的ItemSource,现在,我有了一个comboBoxItem的控制模板,根据我的选择,我的ComboBoxitem控制模板有很多可视化的定制和效果。
下面是我的ComboBoxItem控件模板:
<Style x:Key="{x:Type ComboBoxItem}" TargetType="{x:Type ComboBoxItem}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="UseLayoutRounding" Value="True"/>
<Setter Property="RenderOptions.BitmapScalingMode" Value="NearestNeighbor"/>
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled"/>
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="FontSize" Value="9"/>
<Setter Property="TextOptions.TextFormattingMode" Value="Display"/>
<Setter Property="Foreground" Value="#939393"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Grid>
<Border x:Name="gd" Background="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}},Path=Background}" BorderThickness="0" SnapsToDevicePixels="True" UseLayoutRounding="True" RenderOptions.BitmapScalingMode="NearestNeighbor" RenderOptions.ClearTypeHint="Enabled">
<ContentPresenter
Name="ContentSite" Margin="25, 3, 0, 11" VerticalAlignment="Center">
<ContentPresenter.ContentTemplate>
<DataTemplate>
<TextBlock SnapsToDevicePixels="True" UseLayoutRounding="True" RenderOptions.BitmapScalingMode="HighQuality" RenderOptions.EdgeMode="Aliased">
<Run Text="{Binding Name}"/>
</TextBlock>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
</Border>
<Rectangle x:Name="Border1" Width="12.2" Height="11" Margin="-220,-7,0,0" RenderOptions.BitmapScalingMode="HighQuality" RenderOptions.ClearTypeHint="Auto" SnapsToDevicePixels="True" RenderOptions.EdgeMode="Unspecified">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup x:Name="DrawingLayer">
<DrawingGroup.ClipGeometry>
<RectangleGeometry Rect="0,0,512,512" />
</DrawingGroup.ClipGeometry>
<DrawingGroup Transform="0.1,0,0,-0.1,0,512">
<GeometryDrawing Brush="#d0021b">
<GeometryDrawing.Geometry>
<PathGeometry FillRule="Nonzero" Figures="M4670,3950L2560,1350 1560,2570 830,2190 2590,170 5140,3260 4670,3950z" />
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<Pen Brush="#d0021b" Thickness="0" StartLineCap="Flat" EndLineCap="Flat" LineJoin="Miter" />
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ComboBoxItem.IsMouseOver" Value="True">
<Setter TargetName="gd" Property="Background" Value="#3c3c3c"></Setter>
<Setter TargetName="gd" Property="TextElement.Foreground" Value="#ffffff"></Setter>
<Setter TargetName="gd" Property="SnapsToDevicePixels" Value="True"/>
<Setter TargetName="gd" Property="UseLayoutRounding" Value="True"/>
<Setter TargetName="gd" Property="RenderOptions.BitmapScalingMode" Value="NearestNeighbor"/>
<Setter TargetName="gd" Property="RenderOptions.ClearTypeHint" Value="Enabled"/>
<Setter TargetName="Border1" Property="Visibility" Value="Collapsed"/>
</Trigger>
<Trigger Property="ComboBoxItem.IsMouseOver" Value="False">
<Setter TargetName="Border1" Property="Visibility" Value="Hidden"/>
</Trigger>
<Trigger Property="ComboBoxItem.IsSelected" Value="True">
<Setter TargetName="Border1" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
在我的ComboBoxitem中添加了这个控件模板之后,我的comboBox看起来非常棒。我的ComboBox内容是从List<>
添加的,而不是从ComboBox项中添加的。如果您仔细查看这个控件模板,您可以看到这一行<Run Text="{Binding Name}"/>
,这就是我如何将List<>
绑定到List<>
控件模板中的方式。
我所有的代码运行都很完美,但我的主要问题是如何为该字符串的大写字符和小写字符提供不同的字体大小(字符串是我从Class Audio设备获得的名称)。
我的方法是使用IValueConverter将大写字符和小写字符从字符串"Name“中分离出来。然后,将更大的字体大小提供给大写转换器,将更低的字体大小提供给小写转换器。
就像这样:
<DataTemplate>
<TextBlock SnapsToDevicePixels="True" UseLayoutRounding="True" RenderOptions.BitmapScalingMode="HighQuality" RenderOptions.EdgeMode="Aliased">
<Run x:Name="first" FontSize="18" Text="{Binding Name,Converter={StaticResource UppercaseConverter }}" />
<Run x:Name="rest" FontSize="10" Text="{Binding Name, Converter={StaticResource LowercaseConverter}}" />
</TextBlock>
</DataTemplate>
如果我运行我所有的代码没有任何错误,它会给出默认的音频设备名称,这是在系统中可用的时候。例如,假设它给了我音频设备名称“扬声器(Conexant SmartAudio HD)”。
我想做的是,我想给大写字母不同的字体大小,在字符串扬声器中,"S“是大写字母。我想给字体大小12这个字母"S“,其余的字母”皮克“应该有字体大小10。
我的问题是,这个可用的音频设备名称是动态的,这意味着它不是固定的,如果我在多台计算机上运行我的WPF应用程序,那么它会给出不同的音频设备名称,因为不同的计算机系统有不同的可用音频设备,这是非常常见的。同样重要的是要记住,大写字母的位置是不同的,因为每个设备都有不同的计算机系统。主要的方法应该是如何在动态字符串中为大写字母提供不同的字体大小。
我尝试了很多东西,比如字符串生成器,字符串替换,但是都没有用。任何其他简单的代码建议也是受欢迎的。
我附上了一个屏幕截图,我试图实现,实际上,这些东西已经应用在一个不同的软件,已经在市场上可用。只要看截图,你就能清楚地看到大写字母的字体大小是不同的。
发布于 2022-10-07 20:21:18
可以创建自定义TextBlock并重写其文本属性。
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
namespace WpfApp1;
public class CustomTextBlock : TextBlock
{
public new string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static new readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(CustomTextBlock), new PropertyMetadata(null, (d, ea) =>
{
if (d is TextBlock textBlock)
{
textBlock.Inlines.Clear();
if (ea.NewValue is string value)
{
foreach (char c in value)
{
textBlock.Inlines.Add(new Run { FontSize = GetFontSize(c), Text = c.ToString() });
}
}
}
}));
private static double GetFontSize(char c)
{
// You can add your other logic here
/*if (c == '#')
{
return 5;
}
if (char.IsNumber(c))
{
return 22;
}*/
if (char.IsUpper(c))
{
return 18;
}
return 10;
}
}
您可以通过这种方式在XAML中使用它。我在CustomTextBlock中使用了ComboBox ItemTemplate,但我认为它也应该在ComboBoxItem ControlTemplate中工作。
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ComboBox VerticalAlignment="Top">
<ComboBox.ItemsSource>
<x:Array Type="sys:String">
<sys:String>Some Item #0</sys:String>
<sys:String>Some Item #1</sys:String>
<sys:String>Some Item #2</sys:String>
</x:Array>
</ComboBox.ItemsSource>
<ComboBox.ItemTemplate>
<DataTemplate>
<local:CustomTextBlock Text="{Binding}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</Window>
在您的控制模板中,可以像下面这样使用它。
<DataTemplate>
<local:CustomTextBlock SnapsToDevicePixels="True" UseLayoutRounding="True" RenderOptions.BitmapScalingMode="HighQuality" RenderOptions.EdgeMode="Aliased" Text="{Binding Name}"/>
</DataTemplate>
https://stackoverflow.com/questions/73991056
复制相似问题