I wonder how I can create buttons in my Toolbar by reading lines from a .txt file.
For example:
//bookmarks.txt
http://example.com
http://example2.com
http://example3.com
...
What I want is that my program on start should create a button for each line in my .txt with this event:
public void Button_Click(object sender, RoutedEventArgs e) //fire bookmark event
{
string text = e.Source.ToString().Replace("System.Windows.Controls.Button: ", "");
WebBrowser1.Navigate(text);
}
UPDATE
This is how I read the .txt:
for (int i = 0; i < File.ReadLines(#"bookmarks.txt").Count(); i++)
{
//Add button right here
}
You're trying to use WPF as if it were WinForms. This is how you would fulfil your requirements in WPF... first create a DependencyProperty collection in your Window code behind and populate it with your text entries:
public static DependencyProperty ItemsProperty = DependencyProperty.Register("Items", typeof(ObservableCollection<string>), typeof(YourWindowOrUserControl));
public ObservableCollection<string> Items
{
get { return (ObservableCollection<string>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
...
Items = new ObservableCollection<string>(File.ReadLines(#"bookmarks.txt"));
Then you simply data bind the collection to the ToolBar.ItemsSource property and declare a DataTemplate to define what each string should look like... in your case, we'll set it as the text in a Button:
<ToolBar ItemsSource="{Binding Items}">
<ToolBar.ItemTemplate>
<DataTemplate>
<Button Content="{Binding}" Margin="1,0,0,0" />
</DataTemplate>
</ToolBar.ItemTemplate>
</ToolBar>
Of course, you'll need to set the Window.DataContext to the class with your properties... the simplest way is to set it in the code behind constructor like this:
public YourWindowOrUserControl
{
InitializeComponent();
DataContext = this;
}
You must read up about how to set the DataContext properly though, as setting it this way is easy, but not necessarily correct.
Finally, you could create a class with all the necessary properties for the Button... for example, you could add a property named Text and another called Command and then make your Items property a collection of those. Then you could data bind to it like this:
<ToolBar ItemsSource="{Binding Items}">
<ToolBar.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Text}" Command="{Binding Command}" Margin="1,0,0,0" />
</DataTemplate>
</ToolBar.ItemTemplate>
</ToolBar>
You can create buttons dynamic and add click event on fly:
Button btn = new Button();
btn.Location = new Point(yourX, yourY);
btn.Font = new Font(btn.Font.Name, 10);
btn.Text = "Text from your txt file here";
btn.ForeColor = Color.SeaShell; // choose color
btn.AutoSize = true;
btn.Click += (sender, eventArgs) =>
{
string text = btn.Text.Replace("System.Windows.Controls.Button: ", "");
WebBrowser1.Navigate(text);
};
(Insert this code in your For. Btw, you can replace the for with while. see this link)
Related
Starting with the MahApps-Material mashup demo, I'm trying to use a button click event to create a new TabItem from my Views. For now, the CustomTabItem will show text bound to some property from a FancyObject (being served to the View from my FancyTabViewModel). But I've got the DataContext, dependency property or the Binding done wrong.
public void NewTabOnClick(object sender, RoutedEventArgs e)
{
// create my new object from Models
FancyObject fo = new FancyObject();
// create the INofify VM and pass it my object
// the VM has a public VMFancyObject property to serve the fo
FancyTabViewModel fvm = new FancyTabViewModel(fo);
// create the new UserControl and set its context to the VM
CustomTabItem newTab = new CustomTabItem() {
Header = "New tab"
};
newTab.DataContext = fvm;
MainWindowTabs.Items.Add(newTab);
}
And in my <TabItem x:Class="MyProject.Views.CustomTabItem" there is a label so bound: <Label Content="{Binding VMFancyObject.SomeList.Count}"/>
I expect to see the default count of the List created in the FancyObject's constructor. However, after the new tab is created and added to the dragablz:TabablzControl, I just see a blank label.
I also tried <Label DataContext="{Binding Path=DataContext.FancyTabViewModel,RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}" Content="{Binding VMFancyObject.SomeList.Count}" HorizontalAlignment="Left" Margin="341,196,0,0" Foreground="Black" Background="#FF97FF02"/>
I have two pages: the first is mainpage.xaml and the second is favoriteslist.xaml.
In mainpage.xaml I have a text block, which shows some dynamic text automatically.
And I have a button also on mainpage.xaml.
From which I want when I click on that button, text appears on text block should go to favorite list in favoriteslist.xaml page.
If text already favorite, which text appears on text block should be removed from favorite list on button click.
So finally I need help to implement this functionality textblock which shows dynamically already created but I only need to know how to develop add to favorite functionality.
Textblock:
<TextBlock x:Name="StringTextBlock" Text="" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}" />
Button:
<Button Grid.Row="2" x:Name="AddToFavoritesButton"
Content="Add" Style="{StaticResource ButtonStyle2}" Margin="2"
Click="AddToFavoritesButton_Click"/>
C#
private void AddToFavoritesButton_Click(object sender, RoutedEventArgs e)
{
}
Listbox:
<ListBox x:Name="FavoriteListBox" />
I would use IsolatedStorageSettings to store the list and compare the dynamic text to the list in the isolatedstoragesettings upon button click. Then on FavouritesList page, set itemsource of the listbox to the list in IsolatedStorageSettings.So here are the steps to be followed:
1. Create a model/class to set the dynamic text being shown on the text block
public class favourites
{
public string myText { get; set; }
}
2. In the button click event on MainPage.xaml.cs, first set the dynamic text (where ever you are getting it from) to the text block if you need to and then create the list and/or compare
private void AddToFavoritesButton_Click(object sender, RoutedEventArgs e)
{
//your dynamic text set to textblock
StringTextBlock.Text = myDynamicText;
//Set value of your text to member variable of the model/class
favourites f = new favourites();
f.myText = myDynamicText;
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
/*Check if "FavouritesList" key is present in IsolatedStorageSettings
which means already a list had been added. If yes, retrieve the
list, compare each item with your dynamic text, add or remove
accordingly and replace the new list in IsolatedStorageSettings
with same key. */
if (settings.Contains("FavouritesList"))
{
List<favourites> l = (List<favourites>)settings["FavouritesList"];
for(int i = 0; i <= l.Count()-1; i++)
{
if (l[i].Equals(myDynamicText))
{
l.RemoveAt(i);
settings["FavouritesList"] = l;
}
else
{
l.Add(f);
settings["FavouritesList"] = l;
}
}
}
//If no key in IsolatedStorageSettings means no data has been added
//in list and IsolatedStorageSettings. So add new data
else
{
List<favourites> l = new List<favourites>();
l.Add(f);
settings["FavouritesList"] = l;
}
settings.Save();
}
Now all that is left is show the always updated list in the FavouritesList Page. I added a 'NoData' textblock that should be visible when there is nothing in the list. Else the list will be displayed.
In FavouritesList.xaml
<ListBox x:Name="FavoriteListBox" Visibility="Collapsed">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding myText}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Name="NoData"
Text="No Data"
Visibility="Collapsed"
Width="50"
Height="50"/>
In FavouritesList.xaml.cs
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
if (settings.Contains("FavouritesList"))
{
List<favourites> l = (List<favourites>)settings["FavouritesList"];
if(l.Count!= 0)
{
NoData.Visibility = System.Windows.Visibility.Collapsed;
FavoriteListBox.Visibility = System.Windows.Visibility.Visible;
FavoriteListBox.ItemsSource = l;
}
}
else
{
FavoriteListBox.Visibility = System.Windows.Visibility.Collapsed;
NoData.Visibility = System.Windows.Visibility.Visible;
}
I have not tested this but should definitely work. Hope it helps!
I am creating TabItems programmatically without any issue by using the following code:
var tabItem = new TabItem();
tabItem.Header = "My Tab Header";
tabItem.Content = new UserControl1();
MainTabControl.Items.Add(tabItem);
Now when a tab item added to tab control i also want to add image button at the same time with the creation of TabItem aligned at right side. How can i achieve this? thanks in advance.
EDIT:
I have tried a lot and still did not get an idea. following is my tabcontrol in xaml and ObservableCollection. When i run project tabs shows successfully but i don't know how to add images in it because in my tab control in xaml, it does not have TabItems markup and they are displaying automatically when running project. Please view my sample code and transform into my desired result. I wana conclude and close this issue, I Really thanks and appreciate help.
Following is xaml:
<TabControl ItemsSource="{Binding TabItems, Mode=TwoWay}" DisplayMemberPath="Content" HorizontalAlignment="Left" Height="73" Margin="10,25,0,0" VerticalAlignment="Top" Width="312"/>
Following is viewmodel
namespace WpfApplication1.ViewModels
{
public class VMTabControl : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyname)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyname));
}
[![enter image description here][1]][1]}
public VMTabControl()
{
TabItems = new ObservableCollection<clsTabs>(GetList().ToList());
}
private ObservableCollection<clsTabs> _tabItems;
public ObservableCollection<clsTabs> TabItems
{
get { return _tabItems; }
set
{
_tabItems = value;
OnPropertyChanged("TabItems");
}
}
public List<clsTabs> GetList()
{
List<clsTabs> tablist = new List<clsTabs>();
tablist.Add(new clsTabs { Content = "First", ImgPath = "path" });
tablist.Add(new clsTabs { Content = "Second", ImgPath = "path" });
return tablist;
}
}
}
In code
TabItem.Header is not limited to displaying strings - you can set any UI control on it. For example:
tabItem.Header = new Button { Content = "Click me" };
To display both text and a close button, you could use a horizontal stack panel that contains a text block and a button.
In XAML
However, UI layouts are most often written in XAML. The following XAML assumes you have an Items property in your view model, which is a collection of items. These items have a TabHeaderName and TabImagePath property. The view model should also have a RemoveTabCommand property, which is an ICommand that takes a single argument (the tab item to be removed):
<TabControl ItemsSource="{Binding Items}">
<!-- // If you only need to display a single property, you can use DisplayMemberPath.
// If you need something more fancy (such as a text-block and button next to each other),
// you'll have to provide a tab header template instead: -->
<TabControl.ItemTemplate>
<DataTemplate>
<!-- // Tab item header template (this is how each tab header will look): -->
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding TabHeaderName}" />
<Button Content="X"
Command="{Binding DataContext.RemoveTabCommand, RelativeSource={RelativeSource AncestorType=TabControl}}"
CommandParameter="{Binding}" />
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<!-- // Tab item content template (this is how each tab content will look): -->
<Image Source="{Binding TabImagePath}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
If Items is an observable collection, simply adding an item to it will automatically add a tab item for it. Likewise, removing an item will remove its tab item.
Try this:
var tabItem = new TabItem();
var stack = new StackPanel();
var t = new TextBlock();
t.Text = "My Tab Header";
var i = new Image();
//i.Source = ...
stack.Children.Add(t);
stack.Children.Add(i);
tabItem.Header = stack;
tabItem.Content = new StackPanel();
tab.Items.Add(tabItem);
I'm trying to remove items/rows from a ListView but the difficulty is that I need to also pass in some delegate or fire some event or something, so when a person clicks a button to remove that row, my code handles some other logic, elsewhere (eg. remove the item from the DB or whatever).
I have a custom control I made:
public class SportsTeam : StackLayout { .. }
Inside this control, one of the elements is a ListView which lists all the people in a sporting team.
var viewModel = teamMembers.Select(x => new SportsTeamViewModel(x));
return new ListView
{
HasUnevenRows = true,
ItemSource = viewModel,
ItemTemplate = new DataTemplate(typeof(SportsTeamViewCell));
};
Inside the SportsTeamViewCell I have the following:
private Grid CreateContent()
{
var grid = new Grid();
// Setup row and column definitions.
// Add items to the Grid
grid.Children.Add(...);
var removeButton = RemoveButton;
grid.Children.Add(removeButton);
Grid.SetRowSpan(removeButton, 2);
return grid;
}
private Button RemoveButton
{
get
{
var button = new Button
{
Image = "Icons/remove.png"
};
return button;
}
}
From here, I don't know how to make it so that the button fires an event or some delete could be passed in via the constructor, so some custom logic is performed against the individual cell/row/item that is to be removed.
Here is what you could do :
This be my model class :
public class Item
{
public string ItemName { get; set; }
public string ItemDetails { get; set; }
}
And in my XAML or you can write this in code as well, bind to the Command Parameter of your Item template :
<Button Text="Delete" CommandParameter="{Binding ItemName}" Clicked="DeleteClicked"></Button>
Full Item Template will be like below :
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding ItemName}" HorizontalOptions="StartAndExpand" FontSize="30"></Label>
<Button Text="Delete" CommandParameter="{Binding ItemName}" Clicked="DeleteClicked">
</Button>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
And in you code file you can do this :
public void DeleteClicked(object sender, EventArgs e)
{
var item = (Xamarin.Forms.Button)sender;
Item listitem = (from itm in allItems
where itm.ItemName == item.CommandParameter.ToString()
select itm)
.FirstOrDefault<Item>();
allItems.Remove(listitem);
}
IMPORTANT : This would only delete the item from the bound collection. To delete it from the original list you need to use ObservableCollection
Here is the full source code of the explained scenario - Handling Child Control Event in Listview using XAMARIN.FORMS.
Also the Tutorial - How to handle Row selection and delete Button in Row For Custom ListView using Xamarin.Forms explain deletion from a listview as well.
I've found a similar approach and I want to share it. I filled the list with an ObservableCollection<MyObject>. Then I filled the CommandParameter with just CommandParameter="{Binding .}". So I got the whole Object back. Then you can just cast the CommandParameterto your Object and remove it from the ObservableCollection<MyObject> List
XAML:
CommandParameter="{Binding .}"
Filling my List:
savingExpensesCollection = new ObservableCollection<SavingsExpensesEntry> ();
savingExpensesCollection .Add (new SavingsExpensesEntry ("1000 mAh Akku", "Dampfgarten", new DateTime (635808692400000000), 8.95));
savingExpensesCollection .Add (new SavingsExpensesEntry ("Cool-Mint Aroma", "Dampfgarten", new DateTime (635808692400000000), 3.95));
savingExpensesCollection .Add (new SavingsExpensesEntry ("Basis", "Dampfgarten", new DateTime (635808692400000000), 13.65));
savingExpensesList.ItemsSource = savingExpenses;
EventHandler:
void OnDelete(object sender, EventArgs e)
{
var menuItem = ((MenuItem)sender);
SavingsExpensesEntry see ((SavingsExpensesEntry)menuItem.CommandParameter);
savingExpensesCollection .Remove (see);
}
I've using a MenuItem but it's the same approach with a Button
I just did using delete button
public void OnDelete(object sender, EventArgs e)
{
var mi = ((MenuItem)sender);
PhotoViewModel photo= ((photoViewModel)mi.CommandParameter);
photoModel.Remove(photo);
}
I'm probably not even asking this correctly, I am new to c#, but trying to help my 14 year-old son learn. I've created a listbox with items created with an ObservableCollection. Here is the XAML:
<ListBox x:Name="listBox1" ItemsSource="{Binding}" Margin="105,205,886,63"
IsTabStop="True" SelectionChanged="PrintText"
ScrollViewer.VerticalScrollBarVisibility="Hidden" TabIndex="5" FontSize="36"
Background="Transparent" Foreground="#FF55B64C" FontFamily="Arabic Typesetting"
FontWeight="Bold" IsDoubleTapEnabled="False" SelectionMode="Single" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Name="blockNameList" Text="{Binding name}"/>
<TextBlock Text=" #"/>
<TextBlock Name="blockIdList" Text="{Binding id}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here is how I created the ListBox Items:
var client = new HttpClient();
var uri = new Uri("http://theurlImusing");
Stream respStream2 = await client.GetStreamAsync(uri);
// DataContractJsonSerializer ser2 = new DataContractJsonSerializer(typeof(RootObject));
// RootObject feed2 = (RootObject)ser2.ReadObject(respStream2);
DataContractJsonSerializer ser = null;
ser = new DataContractJsonSerializer(typeof(ObservableCollection<RootObject>));
ObservableCollection<RootObject> feed2 = ser.ReadObject(respStream2) as ObservableCollection<RootObject>;
var cardList = new List<RootObject>();
foreach (RootObject returnfeed in feed2)
{
string cid = returnfeed.id;
string cardname = returnfeed.name;
listBox1.Items.Add(new RootObject { id=cid, name=cardname });
}
I thought I would just use the SelectionChanged="PrintText" property of the listbox so that when I clicked on a listbox item, it would just change a textblock's text value. Ultimately, that is all I am trying to do...set a textblock or textbox to be equal to the "id" value that is clicked on in the ListBox.
void PrintText(object sender, SelectionChangedEventArgs args)
{
//What do I put in here??
}
Thanks very much for any insight! I need it!!
This is something that is much easier to do using data binding. You can bind the TextBlock.Text property directly to the ListBox using an ElementName binding:
<TextBox Text="{Binding ElementName=listBox1,Path=SelectedItem.id}" />
Alternatively, if you set set SelectedValuePath="id" on the ListBox, then binding to SelectedValue will give you the "id" property:
<ListBox x:Name="listBox1" SelectedValuePath="id" ... />
<TextBox Text="{Binding ElementName=listBox1,Path=SelectedValue}" />
As a side note (as #Rachel already noted in comments): you may as well just set the ItemsSource, rather than looping through and adding each manually. All you need is this:
listBox1.ItemsSource = feed2;
Edit
Ok, if you wanted to use the procedural approach, here's how you would do it. (No one would recommend this approach, especially if you're learning/teaching. Try to make full use of data binding, and view-viewmodel separation.)
void PrintText(object sender, SelectionChangedEventArgs args)
{
var listBox = (ListBox)sender;
RootObject selectedItem = listBox.SelectedItem;
someTextBox.Text = selectedItem.id;
}
If all you want to do is click an item in the ListBox and get it to show up in the TextBox, you don't need fancy binding (in that other answer) to do it. You can simply add a MouseUp event in the ListBox XAML:
MouseUp="ListBox1_MouseUp"
This would work similar to the SelectionChanged event you wanted to use.
You then right-click that function name in the XAML page and select "Go to definition". It will create the next function for you:
private void ListBox1_MouseUp(object sender, MouseButtonEventArgs e)
{
}
Simply add in there to update the TextBox you want with the SelectedItem values from sender:
private void ListBox1_MouseUp(object sender, MouseButtonEventArgs e)
{
ListBox lstBox = (ListBox)sender;
ListBoxItem item = lstBox.SelectedItem;
if (item != null) // avoids exception when an empty line is clicked
{
someBox.Text = item.name;
someOtherBox.Text = item.id;
}
}
I later found that blockNameList and blockIdList are not accessible via intellisense because they are within the DataTemplate of the ListBox, so I put someBox and someOtherBox, as references to other TextBoxes you would have to add to the XAML, outside of the ListBox. You would not re-write data inside the ListBox on the same item by clicking it. Even if you could reach the template's TextBlock to do it, you'd just be re-writing that same item with its own values, since it would be the SelectedItem!
Even though there are those that don't recommend this approach because they like binding everything - and in some cases you want binding to occur so that controls on the page update as a result of dependencies (i.e. do one thing to cause another), I find that manual methods of clicking a button/item/control to update something are just fine and avoid all the model/MVVM BS that has taken over WPF and over-complicated it.