I'm working with WPF recently. Now, i'm facing a problem.
I have a button "ADD", every time click on this will add a new row with some contents. Those contents are shown below-
<TextBox Text="{Binding Name}" Margin="10,10" Height="20" ></TextBox>
<TextBox Text="{Binding City}" Margin="10,10" Height="20" ></TextBox>
<TextBox Text="{Binding Age}" Margin="10,10" Height="20"></TextBox>
<TextBox Text="{Binding Count}" Margin="10,10" Height="20" ></TextBox>
<Button Content="M1" Margin="10,10" Height="20"/>
<Button Content="M2" Margin="10,10" Height="20"/>
<Button Content="M3" Margin="10,10" Height="20"/>
</WrapPanel>
</Grid>
Here, at the end there are three buttons M1,M2,M3. But, I don't need this all three buttons every time. I may need only M1 or only M2 or only M3 or M1,M2 etc.
How can I do this in c#?
Actually i don't even know, am i in the right way?
Thanks in advance.
I would highly recommend looking into the MVVM design pattern when working with WPF
That said, I would bind my XAML to an ObservableCollection<SomeObject>, and clicking the AddButton would add a new SomeObject to the ObservableCollection. This would make the UI automatically add the new row when the collection gets updated, and SomeObject could have properties for IsM1Visible, IsM2Visible, and IsM3Visible which determines which buttons are visible.
For example,
Class SomeObject would have
string Name;
string City;
int Age;
int Count;
bool IsM1Visible;
bool IsM2Visible;
bool IsM3Visible;
The XAML would look something like this:
<ItemsControl ItemsSource="{Binding SomeCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBox Text="{Binding Name}" Margin="10,10" Height="20" ></TextBox>
<TextBox Text="{Binding City}" Margin="10,10" Height="20" ></TextBox>
<TextBox Text="{Binding Age}" Margin="10,10" Height="20"></TextBox>
<TextBox Text="{Binding Count}" Margin="10,10" Height="20" ></TextBox>
<Button Content="M1" Visibility="{Binding IsM1Visible, Converter="{StaticResource BooleanToVisibilityConverter}" Margin="10,10" Height="20"/>
<Button Content="M2" Visibility="{Binding IsM2Visible, Converter="{StaticResource BooleanToVisibilityConverter}" Margin="10,10" Height="20"/>
<Button Content="M3" Visibility="{Binding IsM3Visible, Converter="{StaticResource BooleanToVisibilityConverter}" Margin="10,10" Height="20"/>
</WrapPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And the Add Button's Click event would look something like this:
void AddButton_Click(object sender, EventArgs e)
{
var newItem = new SomeItem
{
Name = "Something",
City = "Something",
Age = 30,
Count = 2,
IsM1Visible = true,
IsM2Visible = false,
IsM3Visible = true
};
SomeCollection.Add(newItem);
}
You could use DataBinding if the amount of buttons is dependent on the size of a list/collection.
<ItemsControl ItemsSource={Binding Ms}>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}" Command={Binding ThingToDoWhenClickedCommand}/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This will generate exactly the amount of buttons that is in the Ms collection/List that is in the DataContext.
You can just add the buttons through your code-behind files and put an if structure around the buttons to determine what button should be loaded.
Are you using MVVM?
If so then this is easy. Just create a ButtonViewModel object that represents one of your buttons and expose an ObservableCollection of them from your main ViewModel.
In your view just have a ListView, or just an ItemsControl bound to the collection, and a DataTemplate that turns your ButtonViewModel into a button.
When the user clicks the Add button, add a new ButtonViewModel to your collection and the view will update itself to match.
First, let create a view model for a row. In that model you will have 3 bool properties, IsButton1Visible, IsButton2Visible, IsButton3Visible, or something like that with all properties you need to do binding on your row.
Second, your scenario is that when you click Add, new row will be added. So you have a list of Row_View_Model. On AddCommand, you will at a new Row_View_Model into the list. Here you have full control on what button you want to show.
Related
Needless to say, I am a beginner at Universal Windows Apps development, and I need help. I have a ListView with items representing products displayed as catalog. Each item includes 'Add to Cart' button. My question is: When the button is tapped, how do I pass the specific item for which the button has been tapped to a method which puts the product in the cart. Here is my xaml page:
<ListView Name="productsList">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>...
....
<StackPanel Grid.Column="1" Margin="10">
<TextBlock Name="productName" FontSize="14" Text="{Binding Name}" ></TextBlock>
<TextBlock Name="productPrice" FontSize="14" Text="{Binding Price}" Margin="0,5" ></TextBlock>
<Button Name="addToCart" Content="Stavi u korpu" FontSize="14" Tapped="addToCart_OnTapped" ></Button>
</StackPanel>...
....
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
When the button 'addToCart' is tapped I would like to pass the item as parameter to the following method in C# code, which puts the product in shopping cart:
private void addToCart_OnTapped(object sender, TappedRoutedEventArgs e)
{
// Code to put the product into a cart. This code is not important right now. What is important is how do I pass it a proper parameter?
}
The easiest way for a beginner to solve this is to pass your object as a Tag.
<StackPanel Grid.Column="1" Margin="10">
<TextBlock Name="productName" FontSize="14" Text="{Binding Name}" ></TextBlock>
<TextBlock Name="productPrice" FontSize="14" Text="{Binding Price}" Margin="0,5" ></TextBlock>
<Button Name="addToCart" Tag="{Binding .}" Content="Stavi u korpu" FontSize="14" Tapped="addToCart_OnTapped" ></Button>
</StackPanel>
Binding . refers to the current object in your list.
So on your event you can get the specific button you clicked on, and get the it m out of the Tag.
var button = (Button)sender;
var obj = (Product)button.Tag;
Trying to learn WPF and it's driving me nuts. So I'm trying to do something like the picture that I posted here. But I can only get the combobox, text, checkbox on top of each other and not side by side... How can I do this?
Also I figured out how to add "text" to the listbox if the user pushes a button, but I need it so that when they add text from a textbox. The combobox, checkbox, and button get added with it. But I have no idea how to do that.
I'm assuming I have to make a class for those things. But how do I do that if I'm coding it in XAML? This WPF is confusing for me.
<ListBox HorizontalAlignment="Left" Height="195" Margin="25,345,0,0" VerticalAlignment="Top" Width="650">
<ListBoxItem>
<StackPanel Orientation="Horizontal" Height="45"> <!--Stacks Items Horizontally-->
<ComboBox Width="100" Height="30">
<ComboBoxItem IsSelected="True">DirecTV</ComboBoxItem>
<ComboBoxItem>Hyundai</ComboBoxItem>
<ComboBoxItem>None</ComboBoxItem>
</ComboBox>
<TextBox Width="445" Height="30" Text="Follow RedZone on Twitter" VerticalContentAlignment="Center"/>
<CheckBox IsChecked="True" VerticalAlignment="Center">
<CheckBox.LayoutTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"></ScaleTransform>
</CheckBox.LayoutTransform>
</CheckBox>
<Button Content="Delete" Height="Auto" Width="Auto" HorizontalAlignment="Right" VerticalAlignment="Top" VerticalContentAlignment="Top"/>
</StackPanel>
</ListBoxItem>
</ListBox>
Define a class to hold the items
public class myListBoxRow
{
public string comboBoxSelection {get;set;}
public string textBlockText {get;set;}
public bool checkBoxChecked {get;set;}
}
Now define a ObservableCollection or List somewhere (typically in a ViewModel)
public ObservableCollection myListBoxRows<myListBoxRow> {get;set}
Then bind the ListBox's ItemsSource to your collection
<ListBox ItemsSource="{Binding myListBoxRows}" .../>
To get the controls you want, define an ItemTemplate for your ListBox
<ListBox ItemsSource="{Binding myListBoxRows}" ...>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox ItemsSource="{Binding cboItems}" Width="50" SelectedItem="{Binding comboBoxSelection}" />
<TextBlock Text="{Binding textBlockText}"></TextBlock>
<CheckBox IsChecked="{Binding checkBoxChecked}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Research MVVM in WPF as there are tons of examples of this everywhere. The key part that will tie that together for you is the datatemplate for your listbox/listview
i am trying to make my own mediaplayer for Windows Phone 7 and for the first step, i want to display a List of all songs in my media library to select them.
As i understood the ListBox, i just have to name the texblocks like the attributes of my class, which would be "Song"
<ListBox FontSize="30" Name="songListGUI" Height="330" Margin="0,120,0,0">
<Button Width="430" Height="60" BorderThickness="0" Margin="0" >
<Button.Content>
<StackPanel Orientation="Horizontal" Width="420" Height="auto">
<TextBlock Name="Name" Text="{Binding Name}" FontSize="22"></TextBlock>
<TextBlock Text=" - " FontSize="22"></TextBlock>
<TextBlock Name="Artist" Text="{Binding Artist}" FontSize="22"></TextBlock>
</StackPanel>
</Button.Content>
</Button>
</ListBox>
And now i think, i should handle my list of songs to the GUI and i try to do that with:
songListGUI.ItemsSource = songs;
But then i get a "InvalidOperationException" - Items collection must be empty before using ItemsSource.
I found several problems like this, and they all created a new class, to display this content. But i would like to stick with the song class, as it comes in quite handy :/
Do you know what i am doing wrong here?
edit:
i just found the solution. DonĀ“t know exactly why, but this change in the .xaml made my da :):
<ListBox FontSize="30" Name="songListGUI" Height="330" Margin="0,120,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Width="430" Height="60" BorderThickness="0" Margin="0" >
<Button.Content>
<StackPanel Orientation="Horizontal" Width="420" Height="auto">
<TextBlock Name="Name" Text="{Binding Name}" FontSize="22"></TextBlock>
<TextBlock Text=" - " FontSize="22"></TextBlock>
<TextBlock Name="Artist" Text="{Binding Artist}" FontSize="22"></TextBlock>
</StackPanel>
</Button.Content>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Anybody could explan this to me?
ListBox is an ItemsControl. The content of an ItemsControl maps to the Items property. So by doing this:
<ListBox>
<SomeContent/>
</ListBox>
you're setting the Items property to <SomeContent/>. Since you aren't allowed to set the Items property and the ItemsSource property you get an exception.
When you do this:
<ListBox>
<ListBox.ItemTemplate>...</ListBox.ItemTemplate>
</ListBox>
You're not setting the content you're setting an attribute of the ListBox so there's no conflict.
I'm doing a program that i need to insert two items in the same line of the list view.
That's the XAML code:
<ListView Height="486" HorizontalAlignment="Left" Margin="12,12,0,0" Name="lvTimeline" VerticalAlignment="Top" Width="260">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding}" MaxHeight="48" MaxWidth="48" />
<TextBlock TextWrapping="Wrap" MaxWidth="250" Margin="2,0,2,0" Text="{Binding}" VerticalAlignment="Center" FontSize="14" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have tried infinity ways to do that, but nothing work. What can I do?
The ListView needs an ItemsSource then you bind the Path on the two items. And you can also create columns with a GridView. I like GridView because it sizes columns with headers.
how to get value from the textblock , which is present in listbox ....
here is the code xaml :
<ListBox Height="707" HorizontalAlignment="Left" Margin="12,0,0,0" Name="listBox1" VerticalAlignment="Top" Width="456" Background="White" Foreground="#FF09090C" ItemsSource="{Binding}" SelectionChanged="listBox1_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Name="textBlock3" FontSize="18" Foreground="Blue" Margin="2" Text="{Binding Title.Text}" TextWrapping="Wrap" />
<TextBlock FontSize="16" Foreground="Gray" Margin="2" Text="{Binding Summary.Text}" TextWrapping="Wrap" />
<TextBlock FontSize="1" Foreground="Gray" Margin="2" Text="{Binding Id}" TextWrapping="Wrap" Visibility="Collapsed" />
<Button Name="h1" Content="Press" Height="10" Width="40"></Button>
<TextBlock Foreground="Gray" Margin="2" Text="________________________________________________________________________________________" FontSize="8"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You don't get the value directly from the TextBlock.
Instead what you do is bind the SelectedItem to a property on your viewmodel. To get the value of the TextBlock directly would violate the priciples of MVVM (if you are using that pattern). The viewmodel presents the data, it has no clue how that data is being rendered to the UI. IOW it has no idea there are three TextBlocks.
<ListBox Height="707" SelectedItem={Binding MyViewModelProperty} >
... etc ...
This means that every time the selected item is changed, the new value will be populated into the bound property on the viewmodel. All you have to do then is access that object - it's as easy as that. This means you may also possibly be able to get rid of your SelectionChanged event hookup, depending on what it is doing.
However if you insist on getting the instance of the template used to present any particular data item in a list control, then this is the way to do it programmatically:
myListBox.ItemContainerGenerator.ContainerFromItem(myDataItem);
This will return you the StackPanel and its contents, you can then either use FindName() or just enumerate the child controls to find the one you are interested in.
FrameworkElement element = myListBox.ItemContainerGenerator.ContainerFromItem(myDataItem) as FrameworkElement;
if (element != null)
FrameworkElement child = element.FindName("myChildName");