C# 当获取文本块的高度时,无论实际高度如何,它都会显示相同的数字
我正在制作一个WPF聊天程序,我希望显示消息的方式如下():C# 当获取文本块的高度时,无论实际高度如何,它都会显示相同的数字,c#,wpf,C#,Wpf,我正在制作一个WPF聊天程序,我希望显示消息的方式如下(): 我在做什么: 一个滚动查看器,在网格内部和网格内部有两个堆叠面板,一个用于左侧,一个用于右侧 <ScrollViewer x:Name="scrlViewer" VerticalScrollBarVisibility="Hidden" Width="472" Margin="10,10,0,67" HorizontalAlignment="Left" Grid.ColumnSpan="2"
我在做什么: 一个滚动查看器,在网格内部和网格内部有两个堆叠面板,一个用于左侧,一个用于右侧
<ScrollViewer x:Name="scrlViewer" VerticalScrollBarVisibility="Hidden" Width="472" Margin="10,10,0,67"
HorizontalAlignment="Left" Grid.ColumnSpan="2">
<Grid x:Name="ScrollViewerChild">
<StackPanel x:Name="ChatRow1" Width="200" Margin="10,10,0,10" HorizontalAlignment="Left" />
<StackPanel x:Name="ChatRow2" Width="200" Margin="0,10,10,10" HorizontalAlignment="Right"/>
</Grid>
</ScrollViewer>
问题: “desiredSizeNew”变量似乎每次都是相同的。请注意,我这样得到尺寸是因为试图得到.Height会给我一个NaN,而.ActualHeight总是返回一个零 它总是给我一行(“26.6”)的大小,即使消息包装成多行,因此只要消息只有一行高度,代码就可以工作
任何帮助都将不胜感激!
我希望我能很好地解释我的问题。这是我第一次用c#做任何事情,所以任何关于实现我想要的更好的方法的建议都会很好。尽管我想知道如何首先解决这个问题。我会回答“任何关于更好地实现我想要的目标的建议都会很好” 我认为您应该尝试使用DataTemplate。在代码隐藏中创建元素通常会导致糟糕的结果(大量的工作、未使用的部分、错误行为等) 我的示例基于DataTemplate和两个简单类:
public class Message
{
public string content { get; set; }
public Message(string content)
{
this.content = content;
}
}
public class MsgSent:Message
{
public MsgSent(string content) : base(content) { }
}
public class MsgRecieved : Message
{
public MsgRecieved(string content) : base(content) { }
}
MsgSent
和MsgRecieved
完全相似。但是我们可以想象你聊天时的不同行为。最重要的是,对于DataTemplate,我需要两个不同的类
<ListView ItemsSource="{Binding}" Name="viewChat" HorizontalContentAlignment="Stretch">
<ListView.Resources>
<DataTemplate DataType="{x:Type local:MsgRecieved}">
<Border Background="LightGreen" Width="Auto" HorizontalAlignment="Left" CornerRadius="5" Margin="1">
<TextBlock Text="{Binding content}" Margin="5"/>
</Border>
</DataTemplate>
<DataTemplate DataType="{x:Type local:MsgSent}">
<Border Background="LightBlue" Width="Auto" HorizontalAlignment="Right" CornerRadius="5" Margin="1">
<TextBlock Text="{Binding content}" Margin="5"/>
</Border>
</DataTemplate>
</ListView.Resources>
</ListView>
我使用了一个ObservableCollection,因此您可以动态填充它。为了回答这个问题,
DesiredSize
不是实际高度,在WPF完成其测量和排列过程之前,不会有最终值
但无论如何,您都不会希望这样做,因为没有任何东西可以阻止这些值的更改。例如,如果屏幕旋转,那么宽度可能会改变,这将改变包装,这将改变实际高度…这意味着设置为占位符高度的计算高度现在是错误的
你在试图微观管理布局。让WPF为您做这件事。布局是WPF的工作,而且非常擅长。但是你必须正确地描述布局。一旦你做到了这一点,WPF将在事情发生变化时进行调整。如果您发现自己试图设置宽度或高度,通常需要更仔细地考虑布局。有时你必须这样做,但这应该是罕见的
基本上,您已经定义了两个并排的StackPanel
s。每次消息添加到一侧时,您都会在下面添加一个分隔符,并试图通过放置相应的高分隔符手动保持另一侧的同步
如果您将两侧的项目放置在一个堆叠面板中(而不是两个),那么它将为您整理垂直对齐。然后,您可以将消息向左对齐,将消息向右对齐。作为一个额外的好处,这意味着双方都有更多的宽度可以玩。但是如果您不喜欢,可以限制TextBlock
s的MaxWidth
我还强烈建议您考虑使用MVVM和绑定,而不是在代码隐藏中手动创建控件。同样,这将使您不再需要对不需要的事情进行微观管理。谢谢!我从来没有听说过MVVM,现在我正在读这篇文章。非常感谢!这很好,而且比我之前做的要简单得多:D
public class Message
{
public string content { get; set; }
public Message(string content)
{
this.content = content;
}
}
public class MsgSent:Message
{
public MsgSent(string content) : base(content) { }
}
public class MsgRecieved : Message
{
public MsgRecieved(string content) : base(content) { }
}
<ListView ItemsSource="{Binding}" Name="viewChat" HorizontalContentAlignment="Stretch">
<ListView.Resources>
<DataTemplate DataType="{x:Type local:MsgRecieved}">
<Border Background="LightGreen" Width="Auto" HorizontalAlignment="Left" CornerRadius="5" Margin="1">
<TextBlock Text="{Binding content}" Margin="5"/>
</Border>
</DataTemplate>
<DataTemplate DataType="{x:Type local:MsgSent}">
<Border Background="LightBlue" Width="Auto" HorizontalAlignment="Right" CornerRadius="5" Margin="1">
<TextBlock Text="{Binding content}" Margin="5"/>
</Border>
</DataTemplate>
</ListView.Resources>
</ListView>
ObservableCollection<Message> letsChat = new ObservableCollection<Message>();
letsChat.Add(new MsgRecieved("Hello world! \nHow are you?"));
letsChat.Add(new MsgSent("Hi, good to see you!"));
letsChat.Add(new MsgSent("Hey, are you still there?"));
letsChat.Add(new MsgSent("Please let me know when you are back."));
letsChat.Add(new MsgRecieved("Hello world! \nHow are you?"));
viewChat.DataContext = letsChat;