Why does the ExtentWidth stay at 10.003? - wpf

So I have a ListBox that has a DataTemplate which has a Grid which has a RichTextBox.
For some reason when you type into the RichTextBox it puts each character on a separate line. Digging into this, I find out that the ExtentWidth is equal to 10.003. Why? I have no idea. I was hoping someone could explain to me why and give a nice solution to make it stop doing this.
I did notice that if you set a width on the grid's column, it fixes it, but I don't want a static width on my grid's column.
Below is an example of the problem. I am using .Net 4 and VS 2010.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<ListBox
DockPanel.Dock="Top"
x:Name="TestListBox">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type local:Test}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBox Grid.Column="0" Grid.Row="0" Text="{Binding Name}" />
<TextBlock Grid.Column="1" Grid.Row="0" Text="Test" />
<RichTextBox
Grid.Column="1" Grid.Row="1"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<local:Test Name="Test1" />
<local:Test Name="Test2" />
</ListBox>
using System.Windows;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class Test
{
public string Name { get; set; }
public Test()
{
}
}
}

So I figured out a workaround. If you trade out the ListBox for a DataGrid and use DataGridTemplateColumns with the Width of the TemplateColumn set to "*" then it seems to work.
<DataGrid
x:Name="TestDataGrid"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
>
<DataGrid.Columns >
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<RichTextBox />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<local:Test Name="Test1" />
<local:Test Name="Test2" />
</DataGrid>
Note I also set the CanUserResizeColumns to False because if you don't and they resize them, the ExtentWidth will snap back to 10.

Related

Why is my WPF ContextMenu Item disabled?

I have a small but annoying problem with my ContextMenu in a WPF application.
I use a DataTemplate for my List of ViewModel-objects to create the visual elements. In the DataTemplate I simply set my UserControl like this:
<!-- Define a data-template for the 'RoomViewModel' class. This generates the UI for each node. -->
<DataTemplate DataType="{x:Type model:RoomViewModel}">
<network:RoomView network:ConstraintView.ArgumentChanged="ConstraintView_ArgumentChanged"></network:RoomView>
</DataTemplate>
I want the RoomView to have a ContextMenu where a RelayCommand should be executed if the user clicks on the MenuItem. My UserControl for the RoomView looks like this at the moment:
<UserControl x:Name="userControl" x:Class="NetworkUI.RoomView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:network="clr-namespace:NetworkUI"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" DataContextChanged="userControl_DataContextChanged">
<UserControl.Resources>
<!-- UI commands -->
<RoutedCommand x:Key="Commands.NewConstraintCmd"></RoutedCommand>
</UserControl.Resources>
<UserControl.CommandBindings>
<CommandBinding x:Name="newConst" Command="{StaticResource Commands.NewConstraintCmd}" Executed="NewConstraint_Executed"></CommandBinding>
</UserControl.CommandBindings>
<Grid Width="Auto" Height="Auto" MinWidth="50" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Width="Auto" Height="20" MinWidth="50" >
<Rectangle Stroke="Black" Fill="White" RadiusX="4" RadiusY="4" SnapsToDevicePixels="True" ></Rectangle>
<Grid Margin="-4" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" MinWidth="10" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<network:EditableTextBlock Grid.Column="1" Grid.Row="1" x:Name="nameTextBox" Text="{Binding Name, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Center" BorderBrush="{x:Null}" />
<network:ConnectorItem Grid.Row="1" Grid.Column="0" DataContext="{Binding Connectors[0]}" />
<network:ConnectorItem Grid.Row="1" Grid.Column="2" DataContext="{Binding Connectors[1]}" />
</Grid>
</Grid>
<StackPanel Grid.Row="1" x:Name="roomProperties" Width="Auto" HorizontalAlignment="Stretch" >
<ItemsControl ItemsSource="{Binding PropertyGroups}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<network:ConstraintCollectionView></network:ConstraintCollectionView>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
<UserControl.ContextMenu>
<ContextMenu x:Name="contextMenu">
<MenuItem Header="new Constraint" Command="{StaticResource Commands.NewConstraintCmd}"></MenuItem>
</ContextMenu>
</UserControl.ContextMenu>
</UserControl>
I am not really sure if my UserControl code is ok. In my CodeBehind file I define a
public ICommand NewConstraintCmd;
-Command that should be executed when the user clicks the Item. My Executed handler is simple and looks like this:
private void NewConstraint_Executed(object sender, ExecutedRoutedEventArgs e) {
ViewModel.AddConstraint();
}
The ViewModel is indeed a RoomViewModel and the NewConstraintCmd is set in the DataContextChanged - event (not displayed here).
My simple question is, why is my ContextMenu-Item always disabled? I mean the RelayCommand.CanExecute is never checked, is this the problem maybe?
I didn't find any solution for my problem yet.
Thank you for any help!
Thank you Rohit Vats! I changed my ICommand definition to this:
public static readonly ICommand NewConstraint = new RelayCommand((rvm) => AddConstraint(rvm));
Since this is a static method I needed the parameter (the DataContext of my RoomView).
My Method is defined like this now:
private static void AddConstraint(object rvm) {
if (rvm is RoomViewModel)
(rvm as RoomViewModel).AddConstraint();
}
So first the parameter is checked and if it is ok (a RoomViewModel object) I call the actual function on the object.
I have no idea why it works now, really :/.
My XAML code for the MenuItem now looks like this:
<MenuItem Header="new Constraint" Command="network:RoomView.NewConstraint" CommandParameter="{Binding}"></MenuItem>
As mentioned before I need the CommandParameter to call a function on it. Since the needed Object is my DataContext I just use the {Binding} to pass the object.
This really works fine now, I hope it will work with InputBindings as well in the future :)!
Thank you again for the help!

accordion contenttemplate communication with viewmodel

In a silverlight 5 mvvm project I have the following code:
View:
<navigation:Page x:Class="LobDemo.View.MainView"
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:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="600"
DataContext="{Binding Source={StaticResource Locator}, Path=Main}" >
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<toolkit:DockPanel Grid.Column="0">
<toolkit:Accordion Name="accordion1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding Path=MenuItems}"
Margin="5,5,5,5">
<toolkit:Accordion.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</toolkit:Accordion.ItemTemplate>
<toolkit:Accordion.ContentTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding Path=SubMenuItems}"
Margin="2 2 0 0"
BorderThickness="0"
SelectedItem="{Binding Path=SelectedMenuItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</toolkit:Accordion.ContentTemplate>
</toolkit:Accordion>
</toolkit:DockPanel>
</Grid>
ViewModel: (I'm only showing the required properties)
public ObservableCollection<MenuItem> MenuItems
{
get { return _menuItems; }
set
{
_menuItems = value;
RaisePropertyChanged("MenuItems");
}
}
public object SelectedMenuItem
{
get { return _selectedMenuItem; }
set
{
_selectedMenuItem = value;
RaisePropertyChanged("SelectedMenuItem");
}
}
MenuItem:
public string Name { get; set; }
public ObservableCollection<SubMenuItem> SubMenuItems { get; set; }
SubMenuItem:
public string Name { get; set; }
The code is working fine, my MenuItems are visible in the accordion control, the SubMenuItems are also loaded in the listbox. The problem comes when I select one of the items in the listbox, I want the selected item reported back to my ViewModel as SelectedMenuItem. But the property SelectedMenuItem is never filled, so I'm guessing the code cannot resolve the location of the property.
Can somebody point out what I'm doing wrong?
I found the solution for my problem, I've updated the Accordion.ContentTemplate code in the view, the code now looks like this:
<toolkit:Accordion.ContentTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding Path=SubMenuItems}"
Margin="2 2 0 0"
BorderThickness="0"
SelectedItem="{Binding RelativeSource={RelativeSource AncestorType=navigation:Page}, Path=DataContext.SelectedMenuItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
With this code, the view now finds the SelectedMenuItem property in the ViewModel

Stretching the items in a WPF ListView within a ViewBox

I have a frustrating problem that I would much appreciate some help with. I have a ListView within a ViewBox and I can't get the items within the ListView to stretch horizontally.
Here is the XAML:
<Window x:Class="WpfApplication3.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication3"
Title="Window1">
<Window.Resources>
<local:Inning x:Key="inning">
<local:Inning.Skins>
<local:Skin SkinNumber="1"></local:Skin>
<local:Skin SkinNumber="2"></local:Skin>
<local:Skin SkinNumber="3"></local:Skin>
</local:Inning.Skins>
</local:Inning>
</Window.Resources>
<Grid DataContext="{StaticResource inning}">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Background="Black"
Text="SKINS"
Foreground="White"
FontSize="80"
FontWeight="Bold"
HorizontalAlignment="Center"></TextBlock>
<Grid Margin="2"
Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Viewbox>
<ListView Name="lvSkinNumbers"
ItemsSource="{Binding Skins}"
HorizontalAlignment="Stretch"
Background="Black"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock FontSize="250"
VerticalAlignment="Stretch"
LineStackingStrategy="BlockLineHeight"
Margin="2"
TextAlignment="Center"
HorizontalAlignment="Stretch"
Background="Black"
Foreground="White"
Text="{Binding SkinNumber}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Viewbox>
<Viewbox Grid.Column="1">
<ListView Name="lvFirstInningSkins"
ItemsSource="{Binding Skins}"
Grid.Column="1"
HorizontalContentAlignment="Stretch"
Background="Black">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock FontSize="250"
VerticalAlignment="Stretch"
LineStackingStrategy="BlockLineHeight"
Margin="2"
TextAlignment="Center"
HorizontalAlignment="Stretch"
Background="Green"
Foreground="White"
Text="{Binding SkinNumber}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Viewbox>
<Viewbox Grid.Column="2"
HorizontalAlignment="Stretch">
<ListView Name="lvSecondInningSkins"
ItemsSource="{Binding Skins}"
Grid.Column="2"
HorizontalAlignment="Stretch"
Background="Black">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock FontSize="250"
VerticalAlignment="Stretch"
LineStackingStrategy="BlockLineHeight"
Margin="2"
TextAlignment="Center"
HorizontalAlignment="Stretch"
Background="Green"
Foreground="White"
Text="{Binding SkinNumber}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Viewbox>
</Grid>
</Grid>
</Window>
Here is the code behind with the definitions of the Skin and Inning objects:
using System;
using System.Windows;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace WpfApplication3
{
public class Inning
{
private ObservableCollection<Skin> _skins = new ObservableCollection<Skin>();
public ObservableCollection<Skin> Skins
{
get { return _skins; }
set { _skins = value; }
}
}
public class Skin : INotifyPropertyChanged
{
public Skin()
{
}
public Skin( int skinNumber, Inning inning )
{
this.SkinNumber = skinNumber;
this.Inning = inning;
}
public Inning Inning { get; set; }
public int SkinNumber { get; set; }
public int SkinCount
{
get { return this.Inning.Skins.Count; }
}
public void Notify( string propertyName )
{
if ( PropertyChanged != null )
PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
}
public event PropertyChangedEventHandler PropertyChanged;
}
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
}
The number of skins that can occur in an inning can change, and can be changed by the user, so I've put the ListViews into ViewBoxes so they automatically resize accordingly when the number of skins change. The resulting window can be seen here: http://i52.tinypic.com/244wqpl.jpg
I've tried all sorts of combinations of HorzontalAlignment="Stretch" and HorizontalContentAlignment="Stretch" and tried modifying the ItemsPanel template but I can't for the life of me seem to figure out how to get the ListView to stretch horizontally. Is what I'm trying to do impossible without some code behind to alter the width of the ListView dynamically? Or am I missing something really simple?
Any help that anyone can offer would be most appreciated.
Thanks,
Matthew
Try setting the ItemContainerStyle for your ListView to something like:
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
You also might need to set <Viewbox Stretch="Fill"/>.
After this, I think you can remove all those other "HorizontalAlignment = Stretch" and "HorizontalContentAlignment = Stretch" setters in your code since it probably won't be necessary anymore.
Unexpectedly setting ScrollViewer.HorizontalScrollBarVisibility="Disabled" also worked for me:
<ListView ItemsSource="{Binding SourceList}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">

WPF XAML ComboBox Width

I have the following xaml with all the binding removed;
<StackPanel Grid.Row="2" Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Left" Height="20">
<ComboBox x:Name="ddlDay" Width="30"/>
If I set the width of the combobox to 200 it works but if I set it to 50 it doesn't size past the default.
I'm kinda new to xaml so is this default behavior or what do I do to make the combobox small?
I'm not able to reproduce the behavior you are describing. I tried it with the following test:
<Window x:Class="ComboWidthSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Height="20">
<ComboBox ItemsSource="{Binding}" Width="30" />
<ComboBox ItemsSource="{Binding}" Width="50" />
<ComboBox ItemsSource="{Binding}" Width="200" />
</StackPanel>
</Grid>
</Window>
using System.Linq;
namespace ComboWidthSample
{
public partial class Window1
{
public Window1()
{
InitializeComponent();
DataContext = Enumerable.Range(1, 10).Select(i => "My ComboBox Item " + i).ToList();
}
}
}
Are you doing something different than that? Perhaps databinding to the Width property or styling your ComboBox?

WPF TabStop / TabIndex in ItemsControl

I'm dynamically adding WPF ComboBox-es and I want to be able to select the added ComboBoxes with the 'TAB' key. (Dynamically generate TabIndex or something)
As it actually is:
What I want:
How would you do that?
This is the code:
<ItemsControl ItemsSource="{Binding}" Name="myItemsControl">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ComboBox Grid.Column="0" ItemsSource="{Binding Source={StaticResource SomeItems}}" IsSynchronizedWithCurrentItem="False" SelectedItem="{Binding Path=SomeValue, Mode=TwoWay}" DisplayMemberPath="Name" TabIndex="20"/>
<ComboBox Grid.Column="1" ItemsSource="{Binding Source={StaticResource SomeOtherItems}}" IsSynchronizedWithCurrentItem="False" SelectedItem="{Binding Path=SomeOtherValue, Mode=TwoWay}" DisplayMemberPath="Value" TabIndex="21"/>
<TextBox HorizontalContentAlignment="Stretch" Grid.Column="2" TabIndex="22" LostKeyboardFocus="TextBox_FormatAfterLostFocus">
<TextBox.Text>
<Binding Path="Wert" Mode="TwoWay" />
</TextBox.Text>
</TextBox>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Thanks in advance !
Here is a small example. I did this in Silverlight, so I guess you will have to modify it to work in WPF. It is not complete, but it is a starting point. You might want to use the Tag property on your controls to identify which of them need tab index fixing.
XAML:
<UserControl x:Class="SilverlightApplication6.MainPage"
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"
mc:Ignorable="d"
d:DesignWidth="640"
d:DesignHeight="480">
<Grid x:Name="LayoutRoot">
<StackPanel>
<ItemsControl ItemsSource="{Binding}"
Name="myItemsControl">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ComboBox Grid.Column="0"
ItemsSource="{Binding Source={StaticResource SomeItems}}"
IsSynchronizedWithCurrentItem="False"
SelectedItem="{Binding Path=SomeValue, Mode=TwoWay}"
DisplayMemberPath="Name"
TabIndex="20" />
<ComboBox Grid.Column="1"
ItemsSource="{Binding Source={StaticResource SomeOtherItems}}"
IsSynchronizedWithCurrentItem="False"
SelectedItem="{Binding Path=SomeOtherValue, Mode=TwoWay}"
DisplayMemberPath="Value"
TabIndex="21" />
<TextBox HorizontalContentAlignment="Stretch"
Grid.Column="2"
TabIndex="22">
<TextBox.Text>
<Binding Path="Wert"
Mode="TwoWay" />
</TextBox.Text>
</TextBox>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="Fix Tab indexes" Click="Button_Click"
TabIndex="999"
></Button>
</StackPanel>
</Grid>
</UserControl>
And C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
namespace SilverlightApplication6
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.DataContext = new List<int>() { 1, 2, 3, 4, 5 };
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var controls = new List<Control>();
GetChildrenOfSpecificType<Control>(this, ref controls, false);
var index = 1;
controls.ForEach(control =>
{
if (control is ComboBox || control is TextBox)
{
control.TabIndex = index;
index++;
}
});
}
private static void GetChildrenOfSpecificType<T>(DependencyObject parent, ref List<T> resultList, bool getSingle) where T : class
{
if (parent == null)
return;
else
{
int cnt = VisualTreeHelper.GetChildrenCount(parent);
if (cnt > 0)
{
for (int i = 0; i < cnt; i++)
{
var d = VisualTreeHelper.GetChild(parent, i);
if (d is T)
{
resultList.Add(d as T);
if (getSingle)
return;
}
GetChildrenOfSpecificType<T>(d, ref resultList, getSingle);
}
}
}
}
}
}

Resources