I have this code behind :
private void InitializeListView()
{
//RAZ
lv.Items.Clear();
GridView gridView = new GridView();
gridView.AllowsColumnReorder = true;
GridViewColumn gvc1 = new GridViewColumn();
gvc1.DisplayMemberBinding = new System.Windows.Data.Binding("SN");
gvc1.Header = "SN";
GridViewColumn gvc2 = new GridViewColumn();
gvc2.DisplayMemberBinding = new System.Windows.Data.Binding("a1");
gvc2.Header = "A1";
gridView.Columns.Add(gvc2);
GridViewColumn gvc3 = new GridViewColumn();
gvc3.DisplayMemberBinding = new System.Windows.Data.Binding("a2");
gvc3.Header = "A2";
gridView.Columns.Add(gvc3);
for (int i = 0; i < lv.Count; i++)
{
this.lv.Items.Add(
new dataToUse
{
sn= tab[i][0],
a1= tab[i][1],
a2 = tab[i][2]
});
}
this.lv.View = gridView;
}
in order to generate dinamycally this :
<ListView x:Name="lv" HorizontalAlignment="Left" Height="360" Margin="305,192,0,0" VerticalAlignment="Top" Width="607" SelectionMode="Extended" >
<ListView.View >
<GridView AllowsColumnReorder="true">
<GridViewColumn DisplayMemberBinding="{Binding sn}" >
<GridViewColumnHeader>
<GridViewColumnHeader.ContextMenu>
<ContextMenu>
<MenuItem Header="Asc"/>
<MenuItem Header="Desc" />
</ContextMenu>
</GridViewColumnHeader.ContextMenu>
</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding a1}">
<GridViewColumnHeader >
<GridViewColumnHeader.ContextMenu>
<ContextMenu >
<MenuItem Header="Asc" />
<MenuItem Header="Desc" />
</ContextMenu>
</GridViewColumnHeader.ContextMenu>
</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding a2}">
<GridViewColumnHeader >
<GridViewColumnHeader.ContextMenu>
<ContextMenu >
<MenuItem Header="Asc" />
<MenuItem Header="Desc"/>
</ContextMenu>
</GridViewColumnHeader.ContextMenu>
</GridViewColumnHeader>
</GridViewColumn>
</GridView>
</ListView.View>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
The problem is that when I generate the project, I cannot see the ContextMenu (and so the MenuItems)
I already use this kind of code in another project, but here, it doesn t work...
I guess the code behind is the last one wich is generated, so if you could explain me how to create a ContextMenu programatically. Could be good.
Could you help me please ?
Thanks !
Here is an example for the A2 column. The others follow the same approach.
// Remove:
//gvc3.Header = "A2";
// Replace by:
gvc3.Header = new GridViewColumnHeader()
{
Content = "A2",
ContextMenu = new ContextMenu()
{
Items =
{
new MenuItem() { Header="Asc"},
new MenuItem() { Header="Desc"}
}
}
};
In order to implement the actual sorting with possibility to sort by multiple columns, the menu items could be created with the following helper functions:
private MenuItem CreateAscendingSortMenuItem(string prop)
{
var result = new MenuItem() { Header = "Asc" };
result.Click += (s, e) =>
{
var toRemove = lv.Items.SortDescriptions.Where(x => x.PropertyName == prop).ToList();
foreach (var item in toRemove)
{
lv.Items.SortDescriptions.Remove(item);
}
lv.Items.SortDescriptions.Insert(0, new SortDescription(prop, ListSortDirection.Ascending));
};
return result;
}
private MenuItem CreateDescendingSortMenuItem(string prop)
{
var result = new MenuItem() { Header = "Desc" };
result.Click += (s, e) =>
{
var toRemove = lv.Items.SortDescriptions.Where(x => x.PropertyName == prop).ToList();
foreach (var item in toRemove)
{
lv.Items.SortDescriptions.Remove(item);
}
lv.Items.SortDescriptions.Insert(0, new SortDescription(prop, ListSortDirection.Descending));
};
return result;
}
Then just create the items using the helper function instead of calling the constructor directly.
gvc3.Header = new GridViewColumnHeader()
{
Content = "A2",
ContextMenu = new ContextMenu()
{
Items =
{
CreateAscendingSortMenuItem("a2"),
CreateDescendingSortMenuItem("a2")
}
}
};
Thanks grek40 !
In addtion to your answer (how to create an event for a MenuItem):
// Remove:
//gvc3.Header = "A2";
// Replace by:
MenuItem item1 = New MenuItem();
item1.Header = "Desc";
//Event
item1+= new RoutedEventHandler(this.someFunction_click);
gvc3.Header = new GridViewColumnHeader()
{
Content = "A2",
ContextMenu = new ContextMenu()
{
Items =
{
new MenuItem() { Header="Asc"},
item1
}
}
};
//Function launched by the event
private void someFunction_Click(object sender, System.EventArgs e)
{
//do something
}
Thank you guys for your help !!!
Related
<ComboBox x:Name="Designator"
ItemsSource="{Binding ActiveDesignators}"
DisplayMemberPath="Code"
SelectedValuePath="Code"
SelectedItem="{Binding SelectedUserSearch.Designator,
Converter={StaticResource entityConverter},
ConverterParameter=ActiveDesignators,
Mode=TwoWay}"
Margin="5,0"
Grid.Row="2"
Grid.Column="1"
VerticalAlignment="Center">
<i:Interaction.Behaviors>
<behaviours:SelectorRapidAccessKeyBehavior RapidAccessPropertyName="Code" />
<behaviours:MouseWheelScrollBehaviour />
</i:Interaction.Behaviors>
</ComboBox>
ViewModel:
public FindViewModel (ActiveDesignators activeDesignators,)
{
this.ActiveDesignators = activeDesignators;
this.userService.GetAllUserSearchAsync(this.OnUserSearchLoaded);
}
private void OnUserSearchLoaded(object sender, ServiceEventArgs<IEnumerable<UserSearch>> eea)
{
if (eea.ReturnValue != null)
{
this.currentUserCollection = new EntityCollection<UserSearch>(eea.ReturnValue.Where(u => u.UserId == this.userId));
var collection = new EntityCollection<UserSearch>();
collection.AddRange(this.currentUserCollection.Select(lu => lu.Clone()).Cast<UserSearch>().OrderBy(r => r.Name));
collection.Add(new UserSearch() { Id = -1, Name = WaterMarkAddNewSearch, UserId = this.userId });
this.UserSearchCollection = new EntityCollection<UserSearch>(collection);
this.SelectedUserSearch = this.SetDefaultSearchIfMentioned();
}
}
Data is filling up in the combobox. However selected item is not selecting by default in combobox.
Please help me out why it is not binding selected item value.
I'm having a problem with a ListView for Windows Phone:
I'm using a databinding to display all items in a folder, but when I try to iterate through them, I don't get a control, but the class I use to get the items in the LocalFolder of the app (The subjectpicker class)!
SubjectPicker class:
class SubjectPicker {
public static async Task<List<SubjectPicker>> SubjectData() {
List<string> Names = new List<string>();
List<Brush> Colors = new List<Brush>();
List<string> Items = new List<string>();
List<List<TestOrTask>> TestsAndTasks = new List<List<TestOrTask>>();
StorageFolder LocalFolder = ApplicationData.Current.LocalFolder;
var files = await LocalFolder.GetFilesAsync();
foreach (var file in files) {
//await file.DeleteAsync();
List<TestOrTask> TAT = new List<TestOrTask>();
Names.Add(file.DisplayName);
bool readItems = false;
var contents = await FileIO.ReadLinesAsync(file);
foreach (var content in contents) {
if (content.Contains("Subject Color")) {
string colorname = content.Replace("Subject Color: ", "");
Colors.Add(ColorConverter.fromString_Brush(colorname));
}
else if (content == "<Items>") readItems = true;
else if (content == "</Items>") readItems = false;
if (readItems == true && content != "") {
// Layout: <Name>: <Score>/<Maximum>|<YYYY>/<MM>/<DD>
string name = content.Split(':')[0];
string Score = content.Split(':')[1].Replace(" ", "");
string Date = content.Split('|')[1];
TestOrTask TOT = new TestOrTask(
name,
double.Parse(Score.Split('/')[0]),
double.Parse(Score.Split('/')[1]),
new DateTime(
Int32.Parse(Date.Split('/')[0]),
Int32.Parse(Date.Split('/')[1]),
Int32.Parse(Date.Split('/')[2])));
TAT.Add(TOT);
}
}
Items.Add("Aantal Testen & Taken: " + TAT.Count.ToString());
TestsAndTasks.Add(TAT);
}
var data = new List<SubjectPicker>();
for (int i = 0; i < Names.Count; i++) {
data.Add(new SubjectPicker(Names[i], Colors[i], Items[i], TestsAndTasks[i]));
}
return data;
}
public SubjectPicker(string name, Brush color, string itemstotal, List<TestOrTask> TestsAndTasks) {
PickerName = name;
PickerColor = color;
ItemTotal = itemstotal;
this.TestsAndTasks = TestsAndTasks;
}
public string PickerName { get; set; }
public Brush PickerColor { get; set; }
public string ItemTotal { get; set; }
public List<TestOrTask> TestsAndTasks = new List<TestOrTask>();
}
Xaml Code:
<Page.Resources>
<DataTemplate x:Key="SubjectTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border Margin="0,9.5,0,0" Background="Transparent" >
<Rectangle Height="50" Width="50" Fill="{Binding PickerColor}" RadiusX="5" RadiusY="5"/>
</Border>
<StackPanel Grid.Column="1" Margin="14.5,0,0,0">
<TextBlock Text="{Binding PickerName}" Style="{ThemeResource ListViewItemTextBlockStyle}" />
<TextBlock Text="{Binding ItemTotal}" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" />
</StackPanel>
</Grid>
</DataTemplate>
</Page.Resources>
<Page.BottomAppBar>
<CommandBar x:Name="AppBar" Visibility="Collapsed">
<AppBarButton x:Name="EditSubject" Icon="Edit" Label="Aanpassen" Click="EditSubject_Click"/>
<AppBarButton x:Name="DeleteSubject" Icon="Delete" Label="Verwijderen" Click="DeleteSubject_Click"/>
</CommandBar>
</Page.BottomAppBar>
<Grid x:Name="MainGrid" Loaded="MainGrid_Loaded">
<Controls:TopBarControl x:Name="TopBarControl" Margin="0" VerticalAlignment="Top" PageName="Vakken" ControlsVisible="All" Width="Auto" BackButtonClicked="TopBar_BackButtonClicked" AddButtonClicked="TopBar_AddButtonClicked" EditButtonClicked="TopBar_EditButtonClicked"/>
<Grid x:Name="ControlsGrid" Margin="0,50,0,-60" Tapped="ControlsGrid_Tapped">
<ListView x:Name="SubjectList" ItemsSource="{Binding}" ItemTemplate="{StaticResource SubjectTemplate}"/>
</Grid>
</Grid>
Void to iterate through:
private async Task SelectSubjects() {
for (int i = 0; i < SubjectList.Items.Count; i++) {
var control = SubjectList.Items[i];
Grid subject = control as Grid;
if (subject != null) {
subject.Background = new SolidColorBrush(SchoolToolsColors.AppColor);
await Task.Delay(TimeSpan.FromMilliseconds(50));
}
}
isSelecting = true;
AppBarVisible = Visibility.Visible;
}
Thanks in advance!!!
When iterating on databinded control you'll always get its underlying data.
You should Style.Triggers to alter UI based on data (changing background, showing/hiding controls, etc.).
However, there is a way to go with altering UI from C# but that would make XAML and code-behind tightly coupled => that introduces more complexity into your code - simply believe me, it is not what you want/need.
In my WP8 app, i am using the ListPicker control with multi selection option. In my page, i am loading the Listpicker data from a List of custom classes. And i can able to save what objects are user selected based by implementing the SummaryForSelectedItemsDelegate event and i am saving this info to Isolated storage for later access.
My main problem, how to select the above user selected option when user opened this page where this list picker is there?
I tried using the SelectionChanged event and try to select the object based on stored data, it didn't worked.
<toolkit:ListPicker x:Name="userCountryList" ItemsSource="{Binding CountryList}" Header="Choose a country or region:" SelectionMode="Multiple" FullModeItemTemplate="{StaticResource DataTemplate2}" />
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="DataTemplate2">
<StackPanel Orientation="Horizontal">
<TextBlock HorizontalAlignment="Left" FontSize="28" TextWrapping="Wrap" Text="{Binding CountryName}" VerticalAlignment="Center" Width="Auto"/>
</StackPanel>
</DataTemplate>
Code behind:
var brushes = new List<CustomClass>();
brushes.Add(new CustomClass { CountryCode = "US", CountryName = "United States" });
brushes.Add(new CustomClass { CountryCode = "FR", CountryName = "France" });
brushes.Add(new CustomClass { CountryCode = "DE", CountryName = "Germany" });
brushes.Add(new CustomClass { CountryCode = "CA", CountryName = "Canada" });
userCountryList.SummaryForSelectedItemsDelegate = SummarizeItems;
userCountryList.ItemsSource = brushes;
private string SummarizeItems(IList items)
{
if (items != null && items.Count > 0)
{
string summarizedString = "";
if (items != null)
for (int i = 0; i < items.Count; i++)
{
summarizedString += ((CustomClass )items[i]).CountryCode;
// If not last item, add a comma to seperate them
if (i != items.Count - 1)
summarizedString += ", ";
}
if (!AppSettings.Default.UserSelectedMarkets.Equals(summarizedString))
AppSettings.Default.UserSelectedMarkets = summarizedString;
return summarizedString;
}
else
return "Nothing selected";
}
In your page, override OnNavigatedTo and add all objects to userCountryList.SelectedItems:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
foreach (var o in GetSelectedObjects())
{
userCountryList.SelectedItems.Add(o);
}
base.OnNavigatedTo(e);
}
Let's say I have the follwoing listview in xaml:
<ListView Name="myListView" DataContext="{Binding MyProperty}" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
<ListView.Resources>
<Style TargetType="GridViewColumnHeader">
<Setter Property="Visibility" Value="Collapsed" />
</Style>
</ListView.Resources>
<ListView.View>
<GridView >
<GridViewColumn Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding SomeProperty}" TextAlignment="Center"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
how can I create the same listview with C#?
this is what I have worked out:
ListView myListView = new ListView();
// set bindings
myListView.IsSynchronizedWithCurrentItem = true;
Binding b = new Binding("MyProperty")
{
Source = this
};
myListView.SetBinding(ListView.ItemsSourceProperty, b);
myListView.Resources.Add(; // dont know how to add those resource;
GridView g = new GridView();
GridViewColumn gc = new GridViewColumn();
DataTemplate dt = new DataTemplate(new TextBlock()); // I think this is wrong
g.Columns.Add(gc); // add gridview column
gc.CellTemplate = dt;
myListView.View = g;
Resource adding:
view.Resources.Add(typeof(GridViewColumnHeader),
new Style(typeof(GridViewColumnHeader))
{
Setters =
{
new Setter(GridViewColumnHeader.VisibilityProperty, Visibility.Collapsed)
}
}
);
DataTemplate creating:
var template = new DataTemplate();
var textBlock = new FrameworkElementFactory(typeof(TextBlock));
textBlock.SetBinding(TextBlock.TextProperty, new Binding("SomeProperty"));
textBlock.SetValue(TextBlock.TextAlignmentProperty, TextAlignment.Center);
template.VisualTree = textBlock;
I'm new in WPF and I'd like to visualize data from SQL query to WPF DataGrid.
I have problem with a how correctly bind a data:
SqlCommand cmd = new SqlCommand(sql_dotaz, conn);
InfoText.Text += ("Příkaz vytvořen a připojen" + "\n");
try
{
conn.Open();
InfoText.Text += ("Připojení otevřeno" + "\n");
SqlDataReader reader = cmd.ExecuteReader();
int row_count = reader.FieldCount;
ArrayList propoj = new ArrayList();
for (int i = 0; i < row_count; i++)
{
propoj.Add(reader.GetName(i));
tabView.Columns.Add(new DataGridTextColumn
{
Header = reader.GetName(i),
Binding = new Binding(reader.GetName(i))
});
//Here is the problem!!!
tabView.Items.Add(new {propoj[i] = "Hello"});
}
Problem is when a try to add a new item, it's throws an error. I cannot explicitly set the header name like this (Invitation = "Hello").
I also tried
tabView.Columns.Add(new DataGridTextColumn
{
Header = reader.GetName(i),
Binding = new Binding(reader.GetName(i))
});
string record = reader.GetName(i));
tabView.Items.Add(new {record = "Hello"});
But there is still a problem with the header name - The DataGrid is empty.
Please let me know if you have any ideas.
Thanks a lot!
First of all, I don't think anonymous types will work in a binding. You'll somehow have to create a wrapper object for that:
// easiest case
public class DatabaseObject
{
public List<string> Items = new List<string>();
}
With that, you can easily generate your columns:
// this should be renamed in something like columns or fieldCount...
int row_count = reader.FieldCount;
for (int i = 0; i < row_count; i++)
{
tabView.Columns.Add(new DataGridTextColumn
{
Header = reader.GetName(i),
Binding = new Binding("Items[i]")
});
}
And fill your DataGrid:
if(reader.HasRows)
{
do
{
DatabaseObject obj = new DatabaseObject();
for (int i = 0; i < row_count; i++)
{
obj.Items.Add(reader.GetString(i));
}
tabView.Items.Add(obj);
}
while(reader.NextResult());
}
You need to manage this with DataBinding, as you specified WPF like technology in tags.
Example links :
Link1
Link 2
Link 3
if wanna go the easy way:
fill a datatable with your data.
simply bind the itemssource from the datagrid to your datatable. (Read about DataBinding and MVVM)
<DataGrid ItemsSource="{Binding MyFilledDataTableProperty}" />
set the right datacontext.
In the I find the solution. Maybe it´s not best but it´s work.
I create DataSet and SQL Adapter
adapter.Fill(dSet);
this.DataContext = dSet.Tables[0].DefaultView;
and in XAML:
<DataGrid Height="Auto" Width="Auto" Name="tabView3" ItemsSource="{Binding}" />
And now it´s work fine :-)
This is what worked for me:
IN THE XAML FILE:
<DataGrid Name="YourDataGrid" CanUserAddRows="true" AutoGenerateColumns="False" RowDetailsVisibilityMode="VisibleWhenSelected" Width="auto" SelectionUnit="FullRow" RowEditEnding="YourDataGrid_RowEditEnding" AddingNewItem="YourDataGrid_AddingNewItem">
<DataGrid.Columns>
<DataGridTextColumn x:Name="VideoID_column" Binding="{Binding IDVideo, NotifyOnTargetUpdated=True, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="Video ID" Width="SizeToHeader"/>
<DataGridTextColumn x:Name="VideoTitle_column" Binding="{Binding Titlu,NotifyOnTargetUpdated=True, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="Title" Width="auto"/>
</DataGrid.Columns>
</DataGrid>
IN THE .CS File
private void YourDataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
if (e.EditAction == DataGridEditAction.Commit && isInsertMode == true)
{
var vid = e.Row.DataContext as video;
var context = new YourEntities();
var Video = new video //video is the class
{
IDVideo = vid.IDVideo,
Titlu = vid.Titlu
};
context.videos.Add(Video);
context.SaveChanges();
}
}
private void YourDataGrid_AddingNewItem(object sender, AddingNewItemEventArgs e)
{
isInsertMode = true;
}
Hope that helps!