C# 是否有方法缩放视口,使其内容在控件中显示的所有视口中保持一致?
我使用ViewBox控件和TextBlock控件来显示我使用的应用程序中存在的大多数文本 我遇到的问题是,在大多数情况下,效果不是很好。有些文本可能比其他文本大得多,这并不理想。我也不能只在所有文本中指定字体,因为我不知道用户的硬件,而ViewBox似乎是理想的解决方案,除了这个问题 我创建了一个C# 是否有方法缩放视口,使其内容在控件中显示的所有视口中保持一致?,c#,wpf,scaling,viewbox,C#,Wpf,Scaling,Viewbox,我使用ViewBox控件和TextBlock控件来显示我使用的应用程序中存在的大多数文本 我遇到的问题是,在大多数情况下,效果不是很好。有些文本可能比其他文本大得多,这并不理想。我也不能只在所有文本中指定字体,因为我不知道用户的硬件,而ViewBox似乎是理想的解决方案,除了这个问题 我创建了一个Behavior类来管理这个问题,它在大多数情况下都工作得很好。。。除了现在。这让我相信我的方法并不理想,我希望有人能给我指出一个更“正确”的方向 我正在使用ItemsControl显示一些信息,这就是
Behavior
类来管理这个问题,它在大多数情况下都工作得很好。。。除了现在。这让我相信我的方法并不理想,我希望有人能给我指出一个更“正确”的方向
我正在使用ItemsControl
显示一些信息,这就是问题所在-
符合必要的“要求”
这是窗口代码-
<Window
x:Class="ViewboxScaling.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
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:ViewboxScaling"
mc:Ignorable="d" Title="MainWindow" Height="350" Width="525">
<ItemsControl ItemsSource="{Binding ItemSource, Source={x:Static Application.Current}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="2">
<i:Interaction.Behaviors>
<local:ViewBoxScalingBehavior />
</i:Interaction.Behaviors>
</UniformGrid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Viewbox Margin="5,0" HorizontalAlignment="Left">
<TextBlock Text="{Binding}" />
</Viewbox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
当我运行应用程序时,文本在我只能假设是某种循环(或重复调用
LayoutUpdated
)中来回移动。所以,正如我所说的,如果有其他更可靠的方法来知道什么时候有孩子加入(或移除)一个小组,这将使这变得更容易。这是一个大问题,但我必须在这里列出所有内容。首先,我对所有文本使用ViewBox是错误的方法。在每个文本元素中具有不同“字体大小”的应用程序看起来都很乏味。最好在应用程序启动时选择合适的布局和固定的总字体大小。@Clemens问题是,当控件占用整个窗口(其大小不是静态的)时,使用静态字体大小并不好。我不能只说“好的,字体大小12。那很好”,因为如果窗口只被几个文本块占用(情况就是这样),那么就会有一卡车的死区。不理想。你不能把整个控件放在一个视图框中吗?无论如何,我不会将文本元素增长到荒谬的大尺寸,我会选择不同的布局,并且不会让控件占据整个窗口。@Clemens将整个控件放在一个Viewbox
-这可能正是我需要的。我试试看。但我读到的所有东西都说“使用视口”。可能是我做得不对。我将尝试将ItemControl放在一个viewbox中。首先,对所有文本使用viewbox是错误的方法。在每个文本元素中具有不同“字体大小”的应用程序看起来都很乏味。最好在应用程序启动时选择合适的布局和固定的总字体大小。@Clemens问题是,当控件占用整个窗口(其大小不是静态的)时,使用静态字体大小并不好。我不能只说“好的,字体大小12。那很好”,因为如果窗口只被几个文本块占用(情况就是这样),那么就会有一卡车的死区。不理想。你不能把整个控件放在一个视图框中吗?无论如何,我不会将文本元素增长到荒谬的大尺寸,我会选择不同的布局,并且不会让控件占据整个窗口。@Clemens将整个控件放在一个Viewbox
-这可能正是我需要的。我试试看。但我读到的所有东西都说“使用视口”。可能是我做得不对。我将尝试将ItemControl放在一个viewbox中。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Interactivity;
using System.Windows.Media;
namespace ViewboxScaling {
class ViewBoxScalingBehavior : Behavior<Panel> {
protected override void OnAttached( ) {
//Initially, I would only use the Loaded event.
this.AssociatedObject.Loaded += new RoutedEventHandler(
( S, E ) => this._bindViewBoxHeight( ) );
//However, because of my current use case, I need to know
//whenever the panel has new children added to it.
this.AssociatedObject.LayoutUpdated += new EventHandler(
( S, E ) => this._bindViewBoxHeight( ) );
base.OnAttached( );
}
private void _bindViewBoxHeight( ) {
List<Viewbox> boxes =
FindVisualChildren<Viewbox>(
this.AssociatedObject ).Where(
vb => vb.ActualHeight > 0 &&
vb.Child is FrameworkElement ).ToList( );
foreach ( Viewbox VB in boxes ) {
//Clear bindings and re-set values.
BindingOperations.ClearBinding(
VB, FrameworkElement.HeightProperty );
BindingOperations.ClearBinding(
VB, FrameworkElement.WidthProperty );
VB.Height = double.NaN;
VB.Width = double.NaN;
}
Viewbox
heightSource = boxes.MinBy( vb => vb.ActualHeight ),
widthSource = boxes.MinBy( vb => vb.ActualWidth );
Binding
heightBinding = new Binding( "ActualHeight" ) { Source = heightSource },
widthBinding = new Binding( "ActualWidth" ) { Source = widthSource };
foreach ( Viewbox vb in boxes.Where( box => box != heightSource ) )
BindingOperations.SetBinding(
vb, FrameworkElement.HeightProperty, heightBinding );
foreach ( Viewbox vb in boxes.Where( box => box != widthSource ) )
BindingOperations.SetBinding(
vb, FrameworkElement.WidthProperty, widthBinding );
}
public static List<T> FindVisualChildren<T>( DependencyObject o )
where T : DependencyObject {
List<T> Children = new List<T>( );
for ( int x = 0; x < VisualTreeHelper.GetChildrenCount( o ); x++ ) {
var o2 = VisualTreeHelper.GetChild( o, x );
if ( o2 != null ) {
if ( o2 is T )
Children.Add( ( T )o2 );
Children.AddRange( FindVisualChildren<T>( o2 ) );
}
}
return Children;
}
public static T FindUpVisualTree<T>( DependencyObject initial )
where T : DependencyObject {
DependencyObject current = initial;
while ( current != null && current.GetType( ) != typeof( T ) )
current = VisualTreeHelper.GetParent( current );
return current as T;
}
}
static class VBSExtensions {
public static T MinBy<T, U>( this IEnumerable<T> source, Func<T, U> selector )
where U : IComparable<U> {
if ( source == null ) throw new ArgumentNullException( "source" );
bool first = true;
T minObj = default(T);
U minKey = default(U);
foreach ( var item in source ) {
if ( first ) {
minObj = item;
minKey = selector( minObj );
first = false;
} else {
U currentKey = selector( item );
if ( currentKey.CompareTo( minKey ) < 0 ) {
minKey = currentKey;
minObj = item;
}
}
}
return minObj;
}
}
}
using System.ComponentModel;
using System.Windows;
namespace ViewboxScaling {
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application, INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
private readonly string[] _itemSource = new string[] {
"Text", "Slightly Longer Text"
};
public string[ ] ItemSource {
get { return this._itemSource; }
}
}
}