Binding Button to Listbox Item WPF - c#

I have a GUI containing a listbox that holds rows of missing third party updates that resembles the following
INSTALLBUTTON | POSTPONEBUTTON | Application Name ApplicationVersion Upgrade Message
INSTALLBUTTON | POSTPONEBUTTON | Application Name ApplicationVersion Upgrade Message
Each row contains two buttons (Install and Postpone) as well as several properties read in from a list (application name, version, number of used deferrals, message that is displayed in red). The datacontext for the listbox is a list.
I'm having trouble figuring out how to bind the Install and Postpone buttons to the applications/rows. This is my current WPF:
<ListBox Name="ThirdPartyListBox" ItemsSource="{Binding}" Margin="0,70,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="C:\Users\test\Desktop\Project\ACME-WPF\ACME-WPF\window-new-3.ico" Margin="5" Width="50"/>
<Button Name="ThirdPartyInstallButton" Content="Install" Click="InstallThirdPartyUpdatesButton_Click" Margin="5,5,0,0" Height="25"></Button>
<Button Name="ThirdPartyPostoneButton" Content="Postpone" Margin="5,5,0,0" Height="25"></Button>
<TextBlock FontWeight="Bold" Text="{Binding Item2.Name}" Margin="12,25,0,0"/>
<TextBlock FontWeight="Bold" Text="{Binding Item2.RequiredVersion}" Margin="3,25,0,0"/>
<TextBlock Text="{Binding Item2.CustomUIMessage}" Margin="10,25,0,0" TextWrapping="Wrap" Foreground="Red"/>
<TextBlock Text="You have used " Margin="3,25,0,0"/>
<TextBlock Text="{Binding Item3.UsedDeferrals}" Margin="3,25,0,0"/>
<TextBlock Text=" of " Margin="3,25,0,0"/>
<TextBlock Text="{Binding Item2.MaxDefferals}" Margin="3,25,0,0"/>
<TextBlock Text=" deferrals for this update." Margin="3,25,0,0"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Once the Install button is clicked I need to execute a method that will trigger an install, using a number of the properties of the associated application list item.

In the click handler of the button, call the button .DataContext, that should have your object and its properties.

Instead of using "Click" use the command structures. To get the associated item's data in the command, use the CommandParameter.
CommandParameter="{Binding Path=.}" Command="{Binding ElementName=Root, Path=DataContext.InstallComponentCommand}"
This assumes that the Window/UserControl's is called "Root". Then, in your code-behind set up a "DelegateCommand" to do the work. This blog post contains a great tutorial on how to set it up: http://wpftutorial.net/DelegateCommand.html
The bound component object will show up as the object argument of the delegate.
Update
In the View Model:
public ICommand InstallComponentCommand {get; private set;}
//constructor
{
InstallComponentCommand = new DelegateCommand(p => InstallComponent(p));
}
private void InstallComponent(object data)
{
Component componentToInstall = (Component)data;
// Do whatever is necessary to install
}
As far as disabling the button goes, you could set a property like "InstallInProgress" and bind the "IsEnabled" property of the button to it.
Let me know if I can clarify anything!

Related

Universal Windows App - I have a ListView of products, Add to Cart button.

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;

Windows 8 store app: How dynamically change Binding in ListViewItem

I have created a common control for listView and I want to change the content of each item in the listView. Something like DisplayMemberPath but I need to send two values ​​that are not the same for any one screen.
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Property1}"/>
<TextBlock Text="{Binding Setter2}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
and on the next screen I want something like this
<TextBlock Text="{Binding SuperNewProperty}"/>
<TextBlock Text="{Binding Setter2xyz}"/>
How do I create a control which has variable binding like:
<TextBlock Text="{Binding {Binding MySpecificValue}"/>
This is obviously a stupid thing, but it best describes what I want to do.
For completion:
Ok i have some module Employes.xaml
where call, my control with some dependency properties as itemSource and prop1, prop2(I want to use both, like display member path).
ItemSource is IEnumerable from DB and contains 2 columns: employeName, employNumber, this will be displayed on the listView
<control:listViewMyControl itemSource ="{Binding employes}" prop1="employeName" prop2="employNumber" />
but when i have modul Cities.xaml
I need binding prop1, prop2 to another column name, cityName, cityRank or whatever
<control:listViewMyControl itemSource ="{Binding cities}" prop1="cityName" prop2="cityRank " />
The problem comes when I want to display two different types of listviewitems for listview
// my user control listViewMyControl
<ListView x:Name="listView1">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding employeName}"/>
<TextBlock Text="{Binding employeNumber}"/>
<TextBlock Text="{Binding cityName}"/>
<TextBlock Text="{Binding cityRank}"/>
// but i want only something like display member path for two labels, input modules may be more (employes, cities, cars, stations, .....) something like this
<TextBlock Text="{Binding {Binding MySpecificValue}"/>
<TextBlock Text="{Binding {Binding MySpecificValue2}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Thanks in advance.

Dynamically control the number of buttons in WPF

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.

Getting Listbox Value WP7

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");

Problem when setting up command bindings in XAML

I am trying to create a menu bar for my application. I have created a collection in xaml that I will contain menu items that my menu will bind to.
In xaml I have created an array that I use as my static resource for binding.
<coll:ArrayList x:Key="MenuOptionsList">
<model:DashboardMenuBarItem
Icon="the location of an image in my images folder"
DisplayName="The test that will appear under my button"
CommandName="someCommandInMyViewModel"/>
</coll:ArrayList>
I am using a listbox with a data template to show these items as follows.
<ListBox x:Name="lstNavigateTo" MinWidth="400" DockPanel.Dock="Top"
ItemsSource="{Binding Source={StaticResource MenuOptionsList}}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Style="{StaticResource horizontalListTemplate}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="5">
<Button Height="60" Width="60"
Command="{Binding Mode=OneWay, Path=CommandName}">
<Button.Content>
<Image Source="{Binding Path=Icon}" Grid.Row="0" />
</Button.Content>
</Button>
<TextBlock Text="{Binding Path=DisplayName}"
Width="100" TextAlignment="Center" Grid.Row="1" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My problem is that I am using the MVVM design pattern and cannot get the command bindings to work on the button click. Previously I would have managed the button click like this.
Command="{Binding someCommandInMyViewModel}"
That would work fine but when I try to bind a command to a property of an item in my collection the command will not fire.
Does anyone know how I can achieve this.
The CommandName property in your collection is of type String, whereas the Command property on Button is of type ICommand. In what way are you expecting WPF to resolve an ICommand from a String? You'll need to help it: either create a converter and use it in your binding, or change your CommandName property so that it contains an actual ICommand rather than a String.

Categories