WPF Empty Row in ItemsControl Binding with ObservableCollection - c#

I have ItemsControl Binding to an ObservableCollection, every thing is ok except when ObservableCollection is empty, the ItemsControl will show one empty row !!
<ItemsControl Visibility="Visible" ItemsSource="{Binding ocItemsinInvoice,Mode=TwoWay}"
x:Name="test" Margin="10,-32,0,207" Width="412" HorizontalAlignment="Left">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="1" VerticalAlignment="Top" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button x:Name="btnOpenInvoice" Style="{StaticResource OpenInvoicesButton}"
FontSize="12" Width="300" Height="60" Foreground="#ff252526">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Item.ItemName}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</StackPanel>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
How can I remove it?

public ObservableCollection<object> bindedObservableCollection
{
get{
ObservableCollection<object> newlist = new ObservableCollection<object>(yourObservableCollection);
return newlist;
}
}
I had this issue when binding to a list that was part of a datagrid, I found casting it to a new list of same type removed the blank editors record that is part of the datagrid.

Related

How to bind commands to dynamically added buttons?

How can I bind a delegate command to a dynamically added UserControl button?
I have my UserControl button
<ItemsControl
ItemsSource="{Binding SomeCollection}"
HorizontalAlignment="Center">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid
Columns="2" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<DMX_ControlLibrary:DMX_ItemBox
Width="250"
Height="150"
FontSize="12"
Command="{Binding ItemBoxButtonCommand}"
Content="{Binding Path=.}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And in my view model, I have this
private ICommand itemBoxButtonCommand;
public ICommand ItemBoxButtonCommand
{
get { return (this.itemBoxButtonCommand) ?? (this.itemBoxButtonCommand = new DelegateCommand(ItemButton_Click)); }
}
private void ItemButton_Click()
{
MessageBox.Show("");
}
Binding doesn't seem to work this way unlike it does on statically added controls.
How can I make it work?
As you stated in the comments for ItemBoxButtonCommand:
It's in the viewmodel that contains SomeCollection!
When the data template is applied for each item in the SomeCollection, each DMX_ItemBox will get its DataContext set the the corresponding item, not the data context of the ItemsControl which contains the SomeCollection.
In order to bind to the ItemBoxButtonCommand, you can use a RelativeSource binding to the DataContext of the ItemsControl (which is a parent of the items).
<ItemsControl.ItemTemplate>
<DataTemplate>
<DMX_ControlLibrary:DMX_ItemBox
Width="250"
Height="150"
FontSize="12"
Command="{Binding DataContext.ItemBoxButtonCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"
Content="{Binding Path=.}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
Alternatively, assign an x:Name to the ItemControl and refer to it with ElementName.
<ItemsControl
x:Name="MyItemsControl"
ItemsSource="{Binding SomeCollection}"
HorizontalAlignment="Center">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid
Columns="2" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<DMX_ControlLibrary:DMX_ItemBox
Width="250"
Height="150"
FontSize="12"
Command="{Binding DataContext.ItemBoxButtonCommand, ElementName=MyItemsControl}"
Content="{Binding Path=.}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

WPF MVVM Bind list of different UserControls in Windows page

I am implementing User Controls in my application with MVVM structure. How can I bind different User Controls in a single page and show in a window screen.
Like below image. I want same as it is in the image.
ViewModel code
public RelayCommand OpenWidgetList => new RelayCommand(() =>
{
ControlList = new List<UserControl>();
ControlList.Add(ObjColumn1L);
ControlList.Add(ObjColumn1L);
ControlList.Add(ObjColumn1M);
ControlList.Add(ObjColumn1S);
ControlList.Add(ObjColumn1XL);
ControlList.Add(ObjColumn1XXL);
ControlList.Add(ObjColumn2L);
ControlList.Add(ObjColumn2M);
ControlList.Add(ObjColumn2S);
ControlList.Add(ObjColumn2XL);
ControlList.Add(ObjColumn2XXL);
ControlList.Add(ObjColumn3L);
ControlList.Add(ObjColumn3M);
ControlList.Add(ObjColumn3S);
ControlList.Add(ObjColumn4M);
ControlList.Add(ObjColumn4S);
}, true);
XAML Code
<UniformGrid Name="widgetData" Background="Black" VerticalAlignment="Top" Height="691" Margin="0,50,0,0">
<UniformGrid Columns="3">
<UniformGrid Rows="6">
<UniformGrid>
<ItemsControl ItemsSource="{Binding ControlList}" Name="UserControlColumn" Margin="4,0" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel HorizontalAlignment="Left" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:UserControlColumn HorizontalAlignment="Left" Margin="2" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UniformGrid>
</UniformGrid>
</UniformGrid>
</UniformGrid>
</Grid>
Yes, I found answer.
By coding I tried much but can not do that but in a simple way I had done by XAML side. Nothing but copy the code and separately bind each user Control with only one data from the back-end in DataCollection variable. Without binding each User Control from the back-end codes.
Below are my XAML code of WPF file. where repetedly done for each User Control to bind in the form.
<UniformGrid Rows="1">
<ItemsControl ItemsSource="{Binding DataCollection}" Name="UserControlColumn1" Margin="4,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel HorizontalAlignment="Left" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:UserControlColumn1 HorizontalAlignment="Left" Margin="2" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UniformGrid>
<UniformGrid Rows="1">
<ItemsControl ItemsSource="{Binding DataCollection}" Name="UserControlColumn2" Margin="4,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel HorizontalAlignment="Left" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:UserControlColumn2 HorizontalAlignment="Left" Margin="2" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UniformGrid>
<!--Same for other user Controls as above two...-->
Every user control has its own datacontext so in your main viewmodel you add a property for every usercontrol viewmodel and then you bind it. Something like this:
UserControl1ViewModel
{
....
}
MainViewModel
{
UserControl1ViewModel UserControl1ViewModel {get; private set;}
}

WPF Data Binding ViewModel property to ListBox inside a User Control in code behind

I'm trying to bind dynamically, in code behind, a VM property (an obseravble collection) to image in listBox that sits inside a usercontrol I show on my window,
but it's not working.
This is the XAML of the user control:
<WrapPanel x:Name="panel" HorizontalAlignment="Center" Focusable="False" FocusManager.IsFocusScope="False">
<ListBox x:Name="MazeListBox" ItemsSource="{Binding}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid x:Name="MazeUniformGrid" Columns="{Binding VM_MazeCols}" Rows="{Binding VM_MazeRows}"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image x:Name="Img" Margin="-6" Source="{Binding}" Focusable="False"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</WrapPanel>
This are the usercontrols in XAML of the Outer Window:
<Controls:MazeBoard1 x:Name="you" Margin="0,0,650,0" Grid.Column="0" Height="Auto" Width="Auto" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Controls:MazeBoard1 x:Name="other" Margin="650,0,0,0" Grid.Column="0" Height="Auto" Width="Auto" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center"/>
This is how I bind dynamically in the cs of the window:
Binding youBinding = new Binding
{
Path = new PropertyPath("VM_MazeDisplay"),
};
Binding otherBinding = new Binding
{
Path = new PropertyPath("VM_OtherMazeDisplay"),
};
you.MazeListBox.SetBinding( ContentControl.ContentProperty,youBinding);
other.MazeListBox.SetBinding(ContentControl.ContentProperty, otherBinding);
I'll appreciate your help.
Thank you
Everything looks weird on your XAML...but if you do the following:
you.MazeListBox.SetBinding(ListBox.DataContextProperty, youBinding)
or
you.SetBinding(UserControl.DataContextProperty, youBinding)
or even you.MazeListBox.SetBinding(ListBox.ItemsSourceProperty, youBinding) (you will have to remove the binding into your xaml).
You should have the expected results.
However, why doing a binding in this point and not just only setting the DataContext? Something like you.DataContext = VM_MazeDisplay (assuming the instance of the VM is called that way).
Also, why do you put your ListBox into a WrapPanel?

How to bind StackPanel to a non ObservableCollection?

<StackPanel Orientation="Vertical" x:Name="stackPanel">
<ItemsControl ItemsSource="{Binding C}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Foreground="Black" Text="{Binding prop1}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
I am binding this stack panel to a list with this code
List<C> list = new List<C>();
for (int i = 0; i < 100; i++)
{
list.Add(new C() { prop1 = "prop" });
}
stackPanel.DataContext = list;
And nothing happens. Do we have to always use ObservableCollections? Or what else might be wrong with the code?
The expression {Binding C} doesn't make sense, because you are putting the list itself into the DataContext. Then there is of course no property C.
You should replace it by this:
<ItemsControl ItemsSource="{Binding}">
That said, you aren't actually binding a StackPanel to an items collection, but the ItemsControl inside the StackPanel. If you intended to use the StackPanel as the ItemsPanel of the ItemsControl, you should write it like this:
<ItemsControl x:Name="itemsControl">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Foreground="Black" Text="{Binding prop1}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
and set the ItemsSource like this:
itemsControl.ItemsSource = list;
Remove C in ItemsControl's ItemsSource like this:
<ItemsControl ItemsSource="{Binding}">

Bind datagrid to an ObservableCollection list

I am new with WPF and I would like to bind from xaml to an ObservableCollection. Currently I am doing like this:
in xaml:
<Grid Grid.Column="1">
<local:ProcessingStep DataContext="{Binding ProcessingSteps[0]}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>
<Grid Grid.Column="2">
<local:ProcessingStep DataContext="{Binding ProcessingSteps[1]}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>
<Grid Grid.Column="3">
<local:ProcessingStep DataContext="{Binding ProcessingSteps[2]}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>
in cs:
public ObservableCollection<ProcessingStepView> ProcessingSteps
{
get
{
return m_ProcessingSteps ??
(m_ProcessingSteps = new ObservableCollection<ProcessingStepViewl>
{
new ProcessingStepView("Step1"),
new ProcessingStepView("Step2"),
new ProcessingStepView("Step3")
});
}
}
How can I bind the list directly to wpf? e.g: if I have 100 steps, it is not nice to do one by one.
You can use ItemsControl with ItemTemplate and bind your list:
<ItemsControl ItemsSource="{Binding ProcessingSteps}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:ProcessingStep />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
ItemsControl is basically just a repeater, without selection, that will repeat ItemTemplate as many times as many items there are in ProcessingSteps and place them in whichever panel you choose. In this case horizontal StackPanel

Categories