web.config Binding - An ItemsControl is inconsistent with its items source - wpf

i'm building a tool to display and edit the web.config and want to add an "ADD" Button so that i can add an additional connectionstring to the web.config.
ViewModel:
private ConnectionStringSettingsCollection _ConnectionStrings;
public ConnectionStringSettingsCollection ConnectionStrings
{
get
{
return _ConnectionStrings;
}
set
{
if (_ConnectionStrings != value)
{
_ConnectionStrings = value;
RaisePropertyChanged("ConnectionStrings");
}
}
}
private void ExecuteAddConnectionString()
{
ConnectionStrings.Add(new ConnectionStringSettings("a","b","c"));
}
private void ReadConfig()
{
ConnectionStrings = config.ConnectionStrings.ConnectionStrings;
}
public void CreateConfig()
{
string webDirPath = (PathWithoutFile());
var vdm = new VirtualDirectoryMapping(webDirPath, true, "web.config");
var wcfm = new WebConfigurationFileMap();
wcfm.VirtualDirectories.Add("/", vdm);
config = WebConfigurationManager.OpenMappedWebConfiguration(wcfm, "/");
}
View:
<TabItem Header="ConnectionString">
<GroupBox Header="ConnectionStrings" BorderBrush="Black" BorderThickness="2" Margin="5">
<ListBox ItemsSource="{Binding ConnectionStrings}" Margin="5" Background="Transparent" BorderThickness="0">
<ListBox.ItemTemplate >
<DataTemplate >
<ContentControl >
<vm:ConnectionStringAdd Width="400" Margin="5"/>
</ContentControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</GroupBox>
</TabItem>
So when i click on the Add Button it gives me the following Error:
An ItemsControl is inconsistent with its items source
I know that this is because the GUI doesn't receive a notification about the change, but how do i solve it in my case? Can i somehow make the Connectionstrings to a observable collection?
Many thanks

Related

Caliburn.Micro - Passing combobox items to a button

I'm trying to pass items from my Combobox (which is binded to my Model object's lists) to my button. My problem is that I'm new to Caliburn.Micro + WPF and not quite sure how to subscribe/pass the desired values to my button (like sending strings of a PropetyName to a Button(string propetyName)).
ViewModel code:
class ShellViewModel : Screen
{
private DataModel _fileInFolder;
private BindableCollection<DataModel> _data;
public ShellViewModel()
{
// .GetData() preforms the objects' initialization
DataModel dataOutput = new DataModel();
Data = new BindableCollection<DataModel>(dataOutput.GetData());
}
public BindableCollection<DataModel> Data
{
get
{
return _data;
}
set
{
_data = value;
NotifyOfPropertyChange(() => Data);
}
}
public DataModel FileInFolder
{
get { return _fileInFolder; }
set
{
_fileInFolder = value;
NotifyOfPropertyChange(() => FileInFolder);
}
}
//This is where the items will be passed to.
public void OpenFile()
{
}
}
XAML code:
<Grid>
<!-- Folders -->
<ComboBox ItemsSource="{Binding Data}" SelectedItem="{Binding FileInFolder}"
HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="250">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Folders}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<!-- Files -->
<ComboBox x:Name="FileInFolder_Files"
HorizontalAlignment="Left" Margin="280,10,0,0" VerticalAlignment="Top" Width="250"/>
<!-- Open File -->
<Button x:Name="OpenFile"
Content="Open File" HorizontalAlignment="Left" Margin="560,10,0,0" VerticalAlignment="Top" Width="90">
</Button>
</Grid>
Sorry if my description is vague/missing more clarification, I'm a new user here!
FileInFolder is the selected item of the combo.
OpenFile is in the same class and can therefore reference FileInFolder.
public void OpenFile()
{
var whatever = FileInFolder.SomeProperty;
// etc
}
You probably want some null checking in there.

Upgrade from ListBox to CollectionViewSource not working

I already have a working ListBox with Items from my local database. Now I wanted to upgrade this to a CollectionViewSource for filtering. After my upgrade the new ListBox with CollectionViewSource shows nothing.
MainPage Code Behind:
// Data context for the local database
private BuildingDataContext toDoDB;
// Define an observable collection property that controls can bind to.
private ObservableCollection<Building> _buildings;
public ObservableCollection<Building> BuildingTable
{
get
{
return _buildings;
}
set
{
if (_buildings != value)
{
_buildings = value;
NotifyPropertyChanged("BuildingTable");
}
}
}
public CollectionViewSource Source { get; set; }
// Konstruktor
public MainPage()
{
InitializeComponent();
// Connect to the database and instantiate data context.
toDoDB = new BuildingDataContext(BuildingDataContext.DBConnectionString);
// Data context and observable collection are children of the main page.
this.DataContext = this;
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
// Define the query to gather all of the to-do items.
var toDoItemsInDB = from Building todo in toDoDB.BuildingTable
select todo;
// Execute the query and place the results into a collection.
BuildingTable = new ObservableCollection<Building>(toDoItemsInDB);
Source = new CollectionViewSource();
Source.Source = BuildingTable;
// Call the base method.base.OnNavigatedTo(e);
}
For that purpose I added the lines:
public CollectionViewSource Source { get; set; }
Source = new CollectionViewSource();
Source.Source = BuildingTable;
I tried as well to put
Source = new CollectionViewSource();
Source.Source = BuildingTable;
in my MainPage Constructor. It doesnt work as well.
My Mainpage.xaml:
<!--<ListBox x:Name="toDoItemsListBox" ItemsSource="{Binding BuildingTable}" Grid.Row="0" Margin="12, 0, 12, 0" Width="440" SelectionChanged="goToNavigation">-->
<ListBox x:Name="toDoItemsListBox" ItemsSource="{Binding Source.View}" Grid.Row="0" Margin="12, 0, 12, 0" Width="440" SelectionChanged="goToNavigation">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch" Width="440">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Name="textBlockShortcut" Text="{Binding Shortcut}" Width="Auto" HorizontalAlignment="Left" Grid.Column="0" Margin="0,0,0,5" FontSize="36" />
<TextBlock Name="textBlockName" Text="{Binding BuildingName}" Width="Auto" HorizontalAlignment="Left" Grid.Column="1" Margin="0,0,0,5" FontSize="36" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The first commented line shows the old working listbox without CollectionViewSource. So what am I missing?
EDIT:
private void goToNavigation(object sender, RoutedEventArgs e)
{
// If selected index is -1 (no selection) do nothing
if (toDoItemsListBox.SelectedIndex == -1)
return;
// Navigate to the new page
PhoneApplicationService.Current.State["SelectedItem"] = toDoItemsListBox.SelectedItem;
NavigationService.Navigate(new Uri("/NavigationPage.xaml", UriKind.Relative));
// Reset selected index to -1 (no selection)
toDoItemsListBox.SelectedIndex = -1;
}
You would usually create and bind to a CollectionViewSource in XAML:
<UserControl.Resources>
<CollectionViewSource x:Key="cvs"/>
</UserControl.Resources>
<Grid>
<ListBox ItemsSource="{Binding Source={StaticResource cvs}}" ...>
...
</ListBox>
</Grid>
and in code-behind just access that CollectionViewSource like this:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
...
var cvs = Resources["cvs"] as CollectionViewSource;
cvs.Source = BuildingTable;
}
You don't use the CollectionViewSource class directly, you use a CollectionView of the appropriate type.
View = CollectionViewSource.GetDefaultView( myCollection );
and then you bind that directly to your source.
ItemsSource="{Binding View}"
You can and only should use a CollectionViewSource from xaml, because thats its main purpose. From code you should directly create a CollectionView or use the GetDefaultView method.

Not getting updates as per Selected date in view contains Datagrid binded with Generic List?

I have used tab control for view my usercontrols..
in 1st usercontrol
I have used datagrid to diplay Record and for Binding I have used generic List.
When want to change this List as per selected date then that collection is changed in database and in viewmodel also as List's set propery get executes but in view when i selected new tab and then go back to prevois tab at that time List's get property executes & then i am able get view as per selected date.
My main view and which contain 1st usercontrol as 1st tab item is given below:
Xaml code for above view is given below:
<DataGrid
Background="Transparent"
CanUserAddRows="True"
CanUserReorderColumns="False"
ItemsSource="{Binding Model_Transactions_TransactionsDetails_Jama,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
HeadersVisibility="Column">
</DataGrid>
<Grid DockPanel.Dock="Bottom" VerticalAlignment="Bottom" >
<Border BorderBrush="Black" BorderThickness="1" >
<Label HorizontalAlignment="Left" HorizontalContentAlignment="Right" Width="75" Content="{Binding SumOfWeightJama,UpdateSourceTrigger=PropertyChanged}" FontFamily="Segoe UI" FontWeight="Bold" FontSize="16" />
</Border>
</Grid>
<DataGrid
Background="Transparent"
CanUserAddRows="True"
CanUserReorderColumns="False"
ItemsSource="{Binding Model_Transactions_TransactionsDetails_Udhar,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
HeadersVisibility="Column">
</DataGrid>
<Grid DockPanel.Dock="Bottom" VerticalAlignment="Bottom">
<Border BorderBrush="Black" BorderThickness="1">
<Label Width="75" HorizontalAlignment="Left" HorizontalContentAlignment="Right" Content="{Binding SumOfWeightUdhar,UpdateSourceTrigger=PropertyChanged}" FontFamily="Segoe UI" FontWeight="Bold" FontSize="16"/>
</Border>
</Grid>
And View Model for above View is given below:
private DateTime _FilterDate ;
public DateTime FilterDate
{
get
{
return _FilterDate;
}
set
{
_FilterDate = value;
OnPropertyChanged("FilterDate");
Model_Transactions_TransactionsDetails_Jama = (ViewModel.AllDataCollactions.AllTransactionsDetails.Where(s => s.TransactionDate.Equals(FilterDate) && s.IsJama).OrderBy(s => s.TransactionsID)).ToList();
Model_Transactions_TransactionsDetails_Udhar = (ViewModel.AllDataCollactions.AllTransactionsDetails.Where(s => s.TransactionDate.Equals(FilterDate) && !s.IsJama).OrderBy(s => s.TransactionsID)).ToList();
}
}
public List<Model_TransactionsDetails> Model_Transactions_TransactionsDetails_Jama
{
get
{
return model_Transactions_TransactionsDetails_Jama;
}
set
{
model_Transactions_TransactionsDetails_Jama = value;
OnPropertyChanged("Model_Transactions_TransactionsDetails_Jama");
}
}
public List<Model_TransactionsDetails> Model_Transactions_TransactionsDetails_Udhar
{
get
{
return model_Transactions_TransactionsDetails_Udhar;
}
set
{
model_Transactions_TransactionsDetails_Udhar = value;
OnPropertyChanged("Model_Transactions_TransactionsDetails_Udhar");
}
}
public ViewModel_MasterBook()
{
FilterDate = DateTime.Now.AddDays(-1).Date;
InsertCommand = new RelayCommand(AddExecute, CanAdd);
}
Can any one help me How can i get view as per selected date immediately..
actually it should work i cant see an error. but when i use some kind of Lists in my WPF projects i use observablecollection with clear, add, delete.
but first i would change the binding
ItemsSource="{Binding Model_Transactions_TransactionsDetails_Jama,Mode=OneWay}"
because Mode=TwoWay makes no sense, you never set the itemssource from your datagrid to the viewmodel.
second i would change to ObservableCollection
public ObservableCollection<Model_TransactionsDetails> Model_Transactions_TransactionsDetails_Jama
{
get; private set;
}
with private setter because just initialize once.
//ctor
this.Model_Transactions_TransactionsDetails_Jama = new ObservableCollection<Model_TransactionsDetails>();
and then in your FilterDate setter fill the collection
this.Model_Transactions_TransactionsDetails_Jama.Clear();
var newdata = (ViewModel.AllDataCollactions.AllTransactionsDetails.Where(s => s.TransactionDate.Equals(FilterDate) && s.IsJama).OrderBy(s => s.TransactionsID)).ToList();
this.Model_Transactions_TransactionsDetails_Jama.AddRange(newdata);//AddRange is simply an extension method i wrote, you can simply use foreach and .Add()

Master Detail same View binding controls

say I have a ListView with an ItemControl. And a Details part that shows the selected Item from the ListView. Both are in the same xaml page. I tried everything to accomplish it, but what do I miss?
<!-- // List -->
<ItemsControl ItemsSource="{Binding Path=Model, ElementName=SomeListViewControl, Mode=Default}" SnapsToDevicePixels="True" Focusable="False" IsTabStop="False">
<ItemsControl.ItemTemplate>
<DataTemplate>
<SomeListView:SomeListItemControl x:Name=listItem/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- // Details -->
<Label Content="Begindatum" FontSize="16" VerticalAlignment="Center" Grid.Row="1" Margin="2,0,0,0"/>
<TextBox x:Name="Begindatum" Grid.Column="1" Grid.Row="1" Text="{Binding Path=BeginDate, ElementName=listItem,Converter={StaticResource DateTimeConverter}, ConverterParameter=dd-MM-yyyy}" IsEnabled="False" Style="{DynamicResource TextBoxStyle}" MaxLength="30"/>
public event EventHandler<DataEventArgs<SomeEntity>> OnOpenSomething;
public ObservableCollection<SomeEntity> Model
{
get { return (ObservableCollection<SomeEntity>)GetValue(ModelProperty); }
set
{
Model.CollectionChanged -= new NotifyCollectionChangedEventHandler(Model_CollectionChanged);
SetValue(ModelProperty, value);
Model.CollectionChanged += new NotifyCollectionChangedEventHandler(Model_CollectionChanged);
UpdateVisualState();
}
}
public static readonly DependencyProperty ModelProperty = DependencyProperty.Register("Model", typeof(ObservableCollection<SomeEntity>), typeof(SomeListView), new UIPropertyMetadata(new ObservableCollection<SomeEntity>(), new PropertyChangedCallback(ChangedModel)));
private static void ChangedModel(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
SomeListView someListView = source as SomeListView;
if (someListView.Model == null)
{
return;
}
CollectionView cv = (CollectionView)CollectionViewSource.GetDefaultView(someListView.Model);
}
private void Model_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (Model == null)
{
return;
}
}
Do not use an ItemsControl - ItemsControl does not have a SelectedItem property - and therefore you cannot determine which one is selected.
Use a ListBox instead and then in the detail section make a binding like so: ... DataContext="{Binding SelectedItem,ElementName=ListboxName}" ... where ListboxName is the Name property of the ListBox you use.

wpf binding when using datatemplate

ok currently i have this piece of code:
<TabItem Style="{DynamicResource MyStyle" x:Name="TabCustomers" Padding="0,1,4,1"
Header={Binding Path=customersHeader}/>
Now i want to add an icon there so I do (by removing the header above):
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<Image Stretch="UniformToFill" Source="{StaticResource customers}"/>
<TextBlock x:Key="textblock" Margin="4,0,0,0"
Text="{Binding Path=customersHeader}"/>
</StackPanel>
</TabItem.Header>
So far it's ok.
I would like to generalize this using a datatemplate. I assume i have to do this in my resource dictionary:
<DataTemplate x:Key="TabItemCustomersTemplate" DataType="{x:Type TabItem}">
<StackPanel Orientation="Horizontal">
<Image Stretch="UniformToFill" Source="{StaticResource customers}"/>
<TextBlock x:Key="textblock" Margin="4,0,0,0"
Text="{Binding Path=customersHeader}"/>
</StackPanel>
</DataTemplate>
and change this in my tabitem declaration:
<TabItem ... HeaderTemplate="{StaticResource TabItemCustomersTemplate}".../>
So i run into the following issues and questions:
1) binding doesnt work, why?
2) how can i access textblock from c#?
3) how can i generalize this so i dont have to copy this over and over again for different tab items (or other controls for the matter) so that i can pass my own text and image source each time? For example you might use this to create an image button and if you have 20 buttons the code becomes messy.
Any ideas?
Thank you.
if you template the header in a
tabitem, you do not need to set the
data type of the template. the
header is a property of the tab
item, it is actually a property of
type object, you can put anything in
there.
try removing the DataType="{x:Type
TabItem}" and see if it works.
you should not need to access the
textblock from c#, you should make
do with the binding system. place a
custom object in your header. then
bind this object to your textblock
then adjust the object and it will
manipulate the textblock. getting at
an element is always hard if it is
contained in a data template. you
should not need to. if you find
yourself walking the visual tree to
find a visual element you are doing
things the hard way
you can generalise this by following
suggestion 2, using a custom object,
removing the x:Key of your data
template and setting its DataType to
be the type of your custom object.
then wherever your custom object
appears you will get it data
templated properly
Try this, This is working for me
<Window.Resources>
<!-- <BitmapImage x:Key="customers" UriSource="einstein.jpg"/>-->
<DataTemplate x:Key="TabItemCustomersTemplate">
<StackPanel Orientation="Horizontal">
<Image Stretch="UniformToFill" Source="{Binding Path=Customers}"/>
<TextBlock Margin="4,0,0,0" x:Name="txt" Text="{Binding Path=CustomersHeader}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<TabControl Name="mytabcontrol">
<TabItem x:Name="TabCustomers" Padding="0,1,4,1" Header="{Binding}" HeaderTemplate="{StaticResource TabItemCustomersTemplate}">
<Label Content="myContent" Background="Red"/>
</TabItem>
</TabControl>
</Grid>
in code behind
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
var lst = new List<People>();
lst.Add(new People() { CustomersHeader = "My Customer" });
this.DataContext = lst;
}
}
public class People
{
public string CustomersHeader { get; set; }
public BitmapImage Customers { get; set; }
}
Further you can find your textblock in code behind using this
TabPanel tabPanel = GetVisualChild<TabPanel>(mytabcontrol);
if (tabPanel != null)
{
foreach (UIElement element in tabPanel.Children)
{
TabItem tabItem = element as TabItem;
var image = FindNameFromHeaderTemplate<TextBlock>(tabItem, "txt");
}
}
public static T FindNameFromHeaderTemplate<T>(TabItem tabItem, String name) where T : UIElement
{
if (tabItem == null)
{
throw new ArgumentNullException("container");
}
if (tabItem.HeaderTemplate == null)
{
return null;
}
ContentPresenter contentPresenter = GetVisualChild<ContentPresenter>(tabItem);
if (contentPresenter == null)
{
return null;
}
T element = tabItem.HeaderTemplate.FindName(name, contentPresenter) as T;
return element;
}
public static T GetVisualChild<T>(Visual referenceVisual) where T : Visual
{
Visual child = null;
for (Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(referenceVisual); i++)
{
child = VisualTreeHelper.GetChild(referenceVisual, i) as Visual;
if (child != null && child.GetType() == typeof(T))
{
break;
}
else if (child != null)
{
child = GetVisualChild<T>(child);
if (child != null && child.GetType() == typeof(T))
{
break;
}
}
}
return child as T;
}

Resources