Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
After PivotItem pivotItem = new PivotItem(); I'm getting Additional information: The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD)). What should it be? I'm pretty confused of it.
Code:
foreach (Source source in sources)
{
PivotItem pivotItem = new PivotItem(); /* At this point it falls. */
pivotItem.Header = source.Name;
pivotItem.Margin = new Thickness(0, -10, 0, 0);
ListView listView = new ListView();
listView.ItemsSource = source.Articles;
listView.ItemTemplate = (DataTemplate)Resources["MainItemTemplate"];
listView.ItemClick += OpenArticle_ItemClick;
listView.SelectionMode = ListViewSelectionMode.None;
listView.IsItemClickEnabled = true;
pivotItem.Content = listView;
pvtMain.Items.Add(pivotItem);
}
Based on the exception, you seem to be trying to create a new PivotItem in a thread other than the UI thread. You are only allowed to interact with the UI elements in the UI thread.
You're probably calling this code from an event handler that wasn't triggered from a UI event. You should be able to resolve the issue by using the Dispatcher to switch back to the UI thread:
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
foreach (Source source in sources)
{
PivotItem pivotItem = new PivotItem(); /* At this point it falls. */
pivotItem.Header = source.Name;
pivotItem.Margin = new Thickness(0, -10, 0, 0);
ListView listView = new ListView();
listView.ItemsSource = source.Articles;
listView.ItemTemplate = (DataTemplate)Resources["MainItemTemplate"];
listView.ItemClick += OpenArticle_ItemClick;
listView.SelectionMode = ListViewSelectionMode.None;
listView.IsItemClickEnabled = true;
pivotItem.Content = listView;
pvtMain.Items.Add(pivotItem);
}
});
Related
This question already has answers here:
The calling thread cannot access this object because a different thread owns it
(15 answers)
Closed 5 years ago.
I'm dynamically building my WPF layout and for some reason, when I try to add a control to a grid using a different thread, I'm getting:
System.InvalidOperationException: 'The calling thread cannot access this object because a different thread owns it.'
I know that I need to be invoking my controls if they are being access from different threads and this is what I'm doing.
public void controlInvoke(Grid control, Action action)
{
control.Dispatcher.Invoke((Delegate)action);
}
When I add a new row definition to my grid from the thread, it works fine.
controlInvoke(installedApplicationGrid, () =>
{
installedApplicationGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
});
The children are built from another method, which is below.
private StackPanel BuildAppPanel()
{
StackPanel panel = new StackPanel();
Grid innerGrid = new Grid();
innerGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(50, GridUnitType.Star) });
innerGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(50, GridUnitType.Star) });
innerGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(100, GridUnitType.Star) });
panel.Children.Add(innerGrid);
return panel;
}
The actual code that generates the panel, and tries to add it to my Grid is.
StackPanel applicationPanel = BuildAppPanel();
controlInvoke(installedApplicationGrid, () =>
{
installedApplicationGrid.Children.Add(applicationPanel);
});
It is at this point, when the error message shows. What I don't understand is why this is happening when all of the controls are being dynamically built using this thread. It doesn't make sense to me why adding the row definitions is fine, but adding a new control is not.
Could someone shed some light on this?
So after looking at this a little more carefully, I fixed it by moving the BuildPanel inside of the action.
controlInvoke(installedApplicationGrid, () =>
{
StackPanel applicationPanel = BuildAppPanel();
installedApplicationGrid.Children.Add(applicationPanel);
});
All is working now. Thanks #Fildor for the suggestion.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I need help for item add in the stackpanel.
My item name is "kanal" its wp8 imagebutton item.
Its my codes
public mainpage()
{
InitializeComponent();
foreach (var kanal in MainPage.kanalllarstatik)
{
mystackpanel.Children.Add(kanal);
}
}
I need add 130x130 pixel 3 button items per line like this:
Stackpanel only put one element per line so you need to put a horizontal stackpanel (in each line) and then add to it the three elements.
If you want a 130x130 control, you should use:
kanel.Height=130;
kanal.Width =130;
Code example
Test Data
List<Button> buttons = new List<Button>();
for (int i = 0; i < 16; i++)
{
buttons.Add(new Button
{
Height = 130,
Width = 130,
Content = new TextBlock
{
Text = i.ToString()
}
});
}
Algorithm
StackPanel horizontalStackPanel = new StackPanel
{
Orientation = Orientation.Horizontal
};
foreach (Button button in buttons)
{
horizontalStackPanel.Children.Add(button);
if (horizontalStackPanel.Children.Count == 3) //new line
{
myStackPanel.Children.Add(horizontalStackPanel);
horizontalStackPanel = new StackPanel
{
Orientation = Orientation.Horizontal
};
}
}
myStackPanel.Children.Add(horizontalStackPanel);
XAML
<StackPanel x:Name="myStackPanel"></StackPanel>
Result
I hope that this can help you.
I am using WPF and created a Window with informations about the computer.
It stores informations like Network connectivity, IP's, Subnet masks, Network devices and other stuff.
To track changes in the system I want to add an timer on an object to refresh itself. I don't want to refresh the hole form because I had HttpWebRequests in it and it will freeze the programm for a few seconds. It should be easier to see changes and to highlight them.
For example:
StComputerInf.Children.Add(new Label { Content = "2. Domain: \t\t" + System.Environment.UserDomainName });
I want to add here an timer to refresh itself.
And for every TreeViewItem in a TreeView:
public TreeView CreatTVConnection()
{
List<CAdapter> LAdapter = new List<CAdapter>();
List<TreeViewItem> lConnectedDevices = new List<TreeViewItem>();
List<TreeViewItem> lDisconnectedDevices = new List<TreeViewItem>();
LAdapter = ReadAdapter();
TreeView tv_Adapter = new TreeView();
tv_Adapter.Name = "Adapter";
tv_Adapter.Background = System.Windows.Media.Brushes.Transparent;
tv_Adapter.BorderThickness = new Thickness(0);
TreeViewItem Connected = new TreeViewItem();
TreeViewItem Disconnected = new TreeViewItem();
lConnectedDevices = LoadTV(true, LAdapter);
if (lConnectedDevices.Count > 0)
{
Connected.Header = "Connected:";
Connected.FontWeight = FontWeights.Bold;
Connected.Foreground = System.Windows.Media.Brushes.Green;
Connected.Name = "Connected";
foreach (TreeViewItem tvi in lConnectedDevices)
{
tvi.FontWeight = FontWeights.Normal;
Connected.Items.Add(tvi);
}
}
....
And is there a way to see if an object have changed? So I can highlight the affected object?
Use a factory to create your objects.
So for the label example you'd use something like
LabelFactory.Create(any useful parameters here) and as part of that method you can include a timer etc.
Also, look into using async/await to update your forms as an easier way to update them without freezing the forms. Once you are comfortable with the pattern you should be able to remove the dependency on timers.
I'm a little new to this sort of coding, but i am trying to access dynamically created TextBlock properties (like, TextBlock.Tag, Name, etc) within a StackPanel every tick of a timer. What i intend to do with each TextBlock is to see what its tag property is, and if it matches a conditoinal, for the timer to alter the TextBlock property in some way.
So it's a matter of finding a way to code every timer Tick: "For every TextBlock.Tag in StackPanel, if TextBlock.Tag == this, do this to the TextBlock."
Here is some code to help visualize what I am doing:
Xaml code:
<StackPanel Name="StackP" Margin="6,0,6,0"/>
C# code:
{
for (var i = 0; i < MaxCountOfResults; ++i)
{
TextBlock SingleResult= new TextBlock { Text = Resultname.ToString(), FontSize = 20, Margin = new Thickness(30, -39, 0, 0) };
//a condition to alter certain TextBlock properties.
if (i == .... (irrelevant to this example))
{
SingleResult.Foreground = new SolidColorBrush(Colors.Yellow);
SingleResult.Tag = "00001";
}
//Add this dynamic TextBlock to the StackPanel StackP
StackP.Children.Add(SingleResult);
}
//the timer that starts when this entire function of adding the TextBlocks to the StackPanel StackP tree is done.
Atimer = new Timer(new TimerCallback(Atimer_tick), 0, 0, 100);
}
public void Atimer_tick(object state)
{
The area where I have no idea how to reference the Children of stackpanel StackP with every timer tick. I need help :(
}
Thank you guys. I am still learning this and the help is needed.
you should be able to use timer, but I'd recommend using BackgroundWorker to perform a loop instead of timer events, which could collide. Even better - use SilverLight-style animations with triggers.
On the non-UI thread you'd want to use Dispatcher call to invoke your async code back on the UI thread, something like:
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
try
{
foreach (TextBlock txb in StackP.Children){
txb.Text = "xyz";
}
}
catch (Exception ex)
{
Debug.WriteLine("error: "+ex);
}
});
I'm getting an error when running this code:
tabControl1.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => { tabControl1.Items.Add(tbItem); }));
the tabcontrol1 is hard coded into the xaml and the tab item/s are built at runtime.
I'm getting an error:
TargetInvocationException was
unhandled Exception has been thrown by
the target of an invocation.
I'd love to hear any thoughts on this.
Thanks
UPDATE
the inner exception:
{"The calling thread cannot access
this object because a different thread
owns it."}
the full method code:
TabItem tbItem = new TabItem();
tbItem.Header = worker;
Grid grid = new Grid();
ListBox listBox = new ListBox();
listBox.HorizontalAlignment = HorizontalAlignment.Stretch;
listBox.VerticalAlignment = VerticalAlignment.Stretch;
listBox.ItemsSource = datasource.Where(i => i.Category == worker);
grid.Children.Add(listBox);
tbItem.Content = grid;
tabControl1.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => { tabControl1.Items.Add(tbItem); }));
The method is called with this:
Thread newThread = new Thread(myMethod);
newThread.SetApartmentState(ApartmentState.STA);
newThread.Start();
ANOTHER UPDATE
This works:
tabControl1.Dispatcher.Invoke(DispatcherPriority.Normal,
(Action)(() =>
{
TabItem tbItem = new TabItem();
tbItem.Header = worker;
//Grid & ListBox(within tab item)
Grid grid = new Grid();
ListBox listBox = new ListBox();
listBox.HorizontalAlignment = HorizontalAlignment.Stretch;
listBox.VerticalAlignment = VerticalAlignment.Stretch;
listBox.ItemsSource = datasource.Where(i => i.Category == worker);
grid.Children.Add(listBox);
tbItem.Content = grid;
tabControl1.Items.Add(tbItem);
}));
as you can see your tbItem is created on different thread, even through it tries to dispatch it back to the TAbControl's main gui thread.
why not extract out the part that takes longer (which you are usign thread for) and once you got result back, continue with creating tbItem and adding it to TabControl in the GUI thread
Example:
tabControl.Dispatcher.Invoke calls below function with dataSoruce result it gets
List<string> result = null;
tabControl.Dispatcher.Invoke((Action<IEnumerable<string>>)ProcessResult, result);
public void ProcessResult(IEnumerable<string> datasource)
{
//this is where you do creating TabItem and assigning data source to it and adding to TabControl.
}
Haven't compiled, pls check syntax
Check the InnerException property to find out the reason. TargetInvocationException is just a wrapper by the wpf runtime. Your lambda probably throws, but without the actual exception you can't tell.
edit
You are creating your TabItem in a different thread, thus the GUI thread can't access it, even though you use the dispatcher for the actual adding. As you already posted with your last snippet, you have to create the TabItem in the GUI thread. Only do the calculation in a different thread, and once the result returns, do the actual creation of the TabItem in the GUI thread (if necessary via the Dispatcher).
The problem is that you're creating your UIElements on a separate thread. This is not allowed.
You can do your processing on a background thread (the call to datasource.Where(i => i.Category == worker);), but unfortunately, every UI element needs to be constructed and used entirely on the main user interface thread.
In your case, this means constructing your ListBox and Grid on the UI thread, inside the Dispatcher call.
I would suggest rewriting this as:
// Load the data on the background...
var data = datasource.Where(i => i.Category == worker);
// Do all work on the UI thread
tabControl1.Dispatcher.Invoke(DispatcherPriority.Normal,
(Action)(() =>
{
TabItem tbItem = new TabItem();
tbItem.Header = worker;
//Grid & ListBox(within tab item)
Grid grid = new Grid();
ListBox listBox = new ListBox();
listBox.HorizontalAlignment = HorizontalAlignment.Stretch;
listBox.VerticalAlignment = VerticalAlignment.Stretch;
listBox.ItemsSource = data;
grid.Children.Add(listBox);
tbItem.Content = grid;
tabControl1.Items.Add(tbItem);
}));