这是我第一次使用MVVM pattern
,在理解所有内容之间如何联系时我有些麻烦。
我有一个UserControl
,带有一个Textbox元素,该元素应根据其输入来更改所述UserControl的宽度。
我面临两个问题:
为使我的想法生效,我需要更改并绑定到d:DesignWidth
和我的ColumnDefinition Width
。我如何以及在哪里实施这些更改?根据我对MVVM的了解,该View(在本例中为UserControl)由该UserControl的ViewModel控制。是否有必要实现一个,或者可以直接绑定到这两个属性?我知道我可以用x:Name="MyColumnDefinition"
来命名ColumnDefinition,但是对于实际的UserControl Width来说也一样吗?
mc:Ignorable="d"
d:DesignHeight="60" d:DesignWidth="170">
我有一个ObservableCollection
,里面装有两个不同的UserControl,我希望在显示它们时不要重叠。我使用ListBox
元素来显示ObservableCollection,并使用DataTemplateSelector在DataTemplates上实现不同的UserControls。现在可以正常使用,但是我担心如果我动态更改Control Width,它将与列表中的下一个Control重叠。我如何确保不会发生这种情况?
下面是我现在为UserControl使用的代码:
<Border Background="LightGray" CornerRadius="6">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="70"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<Button VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="0"
BorderThickness="0" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}"
Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DeleteCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DeleteCommandParameter}">
<Rectangle Width="8" Height="8" Fill="White">
<Rectangle.OpacityMask>
<VisualBrush Visual="{StaticResource appbar_close}" Stretch="Fill" />
</Rectangle.OpacityMask>
</Rectangle>
</Button>
<TextBlock Grid.Column="1" Grid.Row="0" FontSize="12" Margin="0,4,0,18" Foreground="White" HorizontalAlignment="Center" Grid.RowSpan="2">Delay</TextBlock>
<TextBox Grid.Column="1" Grid.Row="1" Width="46" Margin="0,4,0,16" HorizontalAlignment="Center" Grid.RowSpan="2"
Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Delay.MiddlePosition, UpdateSourceTrigger=PropertyChanged}"></TextBox>
<TextBlock Grid.Column="1" Grid.Row="2" FontSize="8" Margin="20,5,20,5" Foreground="Gray" HorizontalAlignment="Center">[s]</TextBlock>
</Grid>
</Border>
编辑:
ListBox-XAML来容纳其他UserControls(我正在尝试构建一个可以用自定义Positioning-和DelayControls填充的Axis:
<ListBox Name="Test" SelectionMode="Single" Grid.Column="1"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=BlockList}"
ItemTemplateSelector="{StaticResource BlockTemplateSelector}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Focusable" Value="False"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
最终结果应该看起来像这样,但是定位块和延迟块的大小不同:
答案 0 :(得分:0)
我花了很长时间才弄清楚如何解决您的问题,尽管我对结果不完全满意,但还是设法解决了。
首先,我创建一个带有DummyList的列表框,其中包含一个名为'UserControlModel'的模型对象,其属性为'modelWidth',从中创建其默认大小的UserControl。
<ListBox ItemsSource="{Binding SimpleList, UpdateSourceTrigger=PropertyChanged}" Grid.Row="1" Width="Auto" Height="200">
<ListBox.ItemTemplate>
<DataTemplate>
<osv:UserControl1 Width="{Binding modelWidth}" OnTextValidated="UserControlSizeChangeEvent"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
OnTextValidated是一个RoutedEvent,用于将KeyDown-Event从我的文本框传递到我的窗口(稍后将显示) 然后,UserControl1.xaml添加文本框
<TextBox Width="60" Height="30" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" KeyDown="TextBox_KeyDown" Text="{Binding myText, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"></TextBox>
具有KeyDown事件和文本绑定。
private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Return)//press enter to change
{
if (double.TryParse(myText, out double d) == true)
{
if (d >= 50) //minimum width, so i won't set it to 0 by accident
{
myWidth = d; //set the new Width
OnTextValidated(this, new RoutedEventArgs()); //tell window to resize the UserControl
}
}
}
}
一旦我验证了新的大小既不是错误也不是太小,我称之为RoutedEventHandler
private RoutedEventHandler m_OnTextValidated;
/// <summary>
///
/// </summary>
public RoutedEventHandler OnTextValidated
{
get { return m_OnTextValidated; }
set
{
m_OnTextValidated = value;
OnPropertyChanged("CustomClick");
}
}
现在我可以像上面显示的那样进行绑定了。
接下来我要做的是将事件从xaml.cs传递到MinWindowViewModel
//Variables
private MainWindowViewModel m_DataContext;
//Constructor
DataContext = new MainWindowViewModel ();
m_DataContext = (MainWindowViewModel)this.DataContext;
private void UserControlSizeChangeEvent(object sender, RoutedEventArgs e)
{
if (m_DataContext != null)
{
m_DataContext.UserControlSizeChangeEvent(sender, e);
}
}
最后在后面的代码中更新对象的大小
public void UserControlSizeChangeEvent(object sender, RoutedEventArgs e)
{
UserControl1 uc = sender as UserControl1;
uc.Width = uc.myWidth;
}
注意: 尽管这很好用,但是如果我找到一种改变模型宽度而不是对象宽度的方法,我会更加高兴。如果重新绘制列表,其宽度仍然相同。 我还没有在UserContrl中使用MVVM模式,因此您必须像在MainWindow中一样,首先将事件从xaml.cs传递到您的视图模型中
答案 1 :(得分:-1)
选中此代码将帮助您将一个控件的宽度设置为另一控件。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
Dictionary<long, List<Tuple<object, Object>>> testDict = new Dictionary<long, List<Tuple<object, Object>>>();
testDict.Add(12345 , new List<Tuple<object, object>>(){
new Tuple<object, object>("developer1", "studio1"),
new Tuple<object, object>("developer1", "studio2"),
new Tuple<object, object>("developer1", "studio3")
});
foreach (KeyValuePair<long, List<Tuple<object, Object>>> kvp in testDict)
{
Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
foreach(Tuple<object, Object> tuple in kvp.Value)
{
Console.WriteLine("Item1 = {0}, Item2 = {1}", tuple.Item1, tuple.Item2);
}
}
}
}
}